Spring Boot + AngularJS + Spring Data + JPA CRUD App Example

In this post we will be developing a full-blown CRUD application using Spring Boot, AngularJS, Spring Data, JPA/Hibernate and MySQL, learning the concepts in details along the way. This application can as well serve as a base/starting point for your own application. In addition, we will also use the notion of profiles to deploy the application into two different databases [H2 & MySQL] to emulate the local and production environment, to be more realistic.

springbootcrudapp_img5


Following technologies stack being used:

  • Spring Boot 1.4.3.RELEASE
  • Spring 4.3.5.RELEASE [transitively]
  • Spring data JPA 1.10.6.RELEASE [transitively]
  • Hibernate 5.0.11.Final [transitively]
  • MySQL 5.1.40 [transitively]
  • H2 1.4.187
  • Hikari CP 2.4.7 [transitively]
  • AngularJS 1.5.8
  • Maven 3.1
  • JDK 1.8
  • Eclipse MARS.1

Let’s Begin.

1. Project Structure

springbootcrudapp_img0_1springbootcrudapp_img0_2

2. Dependency Management [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>com.websystique.springboot</groupId>
	<artifactId>SpringBootCRUDApplicationExample</artifactId>
	<version>1.0.0</version>
	<packaging>jar</packaging>

	<name>SpringBootCRUDApplicationExample</name>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.3.RELEASE</version>
	</parent>

	<properties>
		<java.version>1.8</java.version>
		<h2.version>1.4.187</h2.version>
	</properties>

	<dependencies>
		<!-- Add typical dependencies for a web application -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- Add freemarker template support -->		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-freemarker</artifactId>
		</dependency>
		<!-- Add JPA support -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<!-- Add Hikari Connection Pooling support -->
		<dependency>
			<groupId>com.zaxxer</groupId>
			<artifactId>HikariCP</artifactId>
		</dependency>
		<!-- Add H2 database support [for running with local profile] -->
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<version>${h2.version}</version>
		</dependency>
		<!-- Add MySQL database support [for running with PRODUCTION profile] -->		
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
    		<groupId>org.apache.commons</groupId>
    		<artifactId>commons-lang3</artifactId>
    		<version>3.5</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin><!-- Include if you want to make an executable jar[FAT JAR which 
				includes all dependencies along with sprinboot loader] that you can run on 
					commandline using java -jar NAME -->
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

spring-boot-starter-parent : In most of the cases[unless imported], your maven project POM will simply inherit from the spring-boot-starter-parent project. The spring-boot-starter-parent provides useful Maven defaults, provides dependency-management section so that you can omit version tags for dependencies you would need for your own project. Once inherited from spring-boot-starter-parent, you would declare dependencies to one or more “Starters” jars.

spring-boot-starter-web : Provides typical WEB MVC + Embedded container support.

spring-boot-starter-freemarker : Provides freemarker template support. We will be using freemarker in this example.

spring-boot-starter-data-jpa : Provides spring-data setup using JPA abstraction. Since we are talking about fast-development using spring-boot, spring-data would certainly save time compare to traditional DAO/Creteria/Query manual setup.

HikariCP : Provides Hikari connection pooling support. We could have as well used Tomcat datapooling. Common DBCP is usually not recommended for performance reasons.

h2: Provides H2 database support. Please note that it is used here just to demonstrate the real-life scenarios where your local setup uses one database while the one on production might be altogether a different database.Additionally, we are deliberately using a different version of h2, just to demonstrate that you CAN change the dependencies if needed.

mysql-connector-java: Provides MySQL database support. Again, just because we are simulating a local[H2]-Production[MySQL] scenario.

2. Spring Boot Application [Main class]

You read it right. Good old main is what all we need to start our newly created spring boot app. Spring Boot provides SpringApplication class to bootstrap a Spring application that will be started from a main() method using static SpringApplication.run method.

package com.websystique.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;

import com.websystique.springboot.configuration.JpaConfiguration;


@Import(JpaConfiguration.class)
@SpringBootApplication(scanBasePackages={"com.websystique.springboot"})
public class SpringBootCRUDApp {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootCRUDApp.class, args);
	}
}

This class is annotated with @SpringBootApplication which is actually the combination of [shortcut] @EnableAutoConfiguration, @Configuration & @ComponentScan. You can choose either of them.

Spring Boot @EnableAutoConfiguration attempts to automatically configure your Spring application based on the jar dependencies that you have added. Since we have added spring-boot-starter-web, Spring boot will setup the Spring configuration for a web-application.

3. JPA configuation

In this configuration class, we are doing a lot: Creating datasource [using Hikari connection pooling], creating EntityManagerFactory, setting up transaction manager, referring to Spring-data repositories etc.

  • Spring Data @EnableJpaRepositories: @EnableJpaRepositories Annotation enables JPA repositories. It will scan the specified packages for Spring Data repositories. by default, it will look into current package for Spring-data repositories.
  • Spring Boot DataSourceProperties : DataSourceProperties is the helper class for configuration of a data source. Interesting point is that we can map the properties right from .yml files, thanks to hierarchical data. Matching-name properties from .yml will be mapped directly to properties of DataSourceProperties object.
  • Spring Boot DataSourceBuilder : DataSourceBuilder is a builder that can help creating a datasource using the mapped properties.
  • Additionally,if a datasource property is missing in DataSourceProperties [maxPoolSize e.g.], we can still take the advantage of good old @Value annotation to map it form property file to actual object property.
package com.websystique.springboot.configuration;

import java.util.Properties;

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

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
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 com.zaxxer.hikari.HikariDataSource;

@Configuration
@EnableJpaRepositories(basePackages = "com.websystique.springboot.repositories",
		entityManagerFactoryRef = "entityManagerFactory",
		transactionManagerRef = "transactionManager")
@EnableTransactionManagement
public class JpaConfiguration {

	@Autowired
	private Environment environment;

	@Value("${datasource.sampleapp.maxPoolSize:10}")
	private int maxPoolSize;

	/*
	 * Populate SpringBoot DataSourceProperties object directly from application.yml 
	 * based on prefix.Thanks to .yml, Hierachical data is mapped out of the box with matching-name
	 * properties of DataSourceProperties object].
	 */
	@Bean
	@Primary
	@ConfigurationProperties(prefix = "datasource.sampleapp")
	public DataSourceProperties dataSourceProperties(){
		return new DataSourceProperties();
	}

	/*
	 * Configure HikariCP pooled DataSource.
	 */
	@Bean
	public DataSource dataSource() {
		DataSourceProperties dataSourceProperties = dataSourceProperties();
			HikariDataSource dataSource = (HikariDataSource) DataSourceBuilder
					.create(dataSourceProperties.getClassLoader())
					.driverClassName(dataSourceProperties.getDriverClassName())
					.url(dataSourceProperties.getUrl())
					.username(dataSourceProperties.getUsername())
					.password(dataSourceProperties.getPassword())
					.type(HikariDataSource.class)
					.build();
			dataSource.setMaximumPoolSize(maxPoolSize);
			return dataSource;
	}

	/*
	 * Entity Manager Factory setup.
	 */
	@Bean
	public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws NamingException {
		LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
		factoryBean.setDataSource(dataSource());
		factoryBean.setPackagesToScan(new String[] { "com.websystique.springboot.model" });
		factoryBean.setJpaVendorAdapter(jpaVendorAdapter());
		factoryBean.setJpaProperties(jpaProperties());
		return factoryBean;
	}

	/*
	 * Provider specific adapter.
	 */
	@Bean
	public JpaVendorAdapter jpaVendorAdapter() {
		HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
		return hibernateJpaVendorAdapter;
	}

	/*
	 * Here you can specify any provider specific properties.
	 */
	private Properties jpaProperties() {
		Properties properties = new Properties();
		properties.put("hibernate.dialect", environment.getRequiredProperty("datasource.sampleapp.hibernate.dialect"));
		properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("datasource.sampleapp.hibernate.hbm2ddl.method"));
		properties.put("hibernate.show_sql", environment.getRequiredProperty("datasource.sampleapp.hibernate.show_sql"));
		properties.put("hibernate.format_sql", environment.getRequiredProperty("datasource.sampleapp.hibernate.format_sql"));
		if(StringUtils.isNotEmpty(environment.getRequiredProperty("datasource.sampleapp.defaultSchema"))){
			properties.put("hibernate.default_schema", environment.getRequiredProperty("datasource.sampleapp.defaultSchema"));
		}
		return properties;
	}

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

}

4. Property file [application.yml]

Although traditional .properties would just do fine, Spring Boot’s SpringApplication class also supports YAML out of the box provided SnakeYAML library is on class-path which usually would be due to starters. YAML is a superset of JSON, and as such is a very convenient format for specifying hierarchical configuration data. YAML file is also known as streams, containing several documents, each separated by three dashes (—). A line beginning with “—” may be used to explicitly denote the beginning of a new YAML document.YAML specification is a good read to know more about them.

src/main/resources/application.yml

server:
  port: 8080
  contextPath: /SpringBootCRUDApp
---
spring:
  profiles: local,default
datasource:
  sampleapp:
    url: jdbc:h2:~/test
    username: SA
    password:
    driverClassName: org.h2.Driver
    defaultSchema:
    maxPoolSize: 10
    hibernate:
      hbm2ddl.method: create-drop
      show_sql: true
      format_sql: true
      dialect: org.hibernate.dialect.H2Dialect
---
spring:
  profiles: prod
datasource:
  sampleapp:
    url: jdbc:mysql://localhost:3306/websystique
    username: myuser
    password: mypassword
    driverClassName: com.mysql.jdbc.Driver
    defaultSchema:
    maxPoolSize: 20
    hibernate:
      hbm2ddl.method: update
      show_sql: true
      format_sql: true
      dialect: org.hibernate.dialect.MySQLDialect
  • Since our app will be running on an Embedded container, we would need a way to configure the port and context-path for our app. By-default, Spring-Boot will use no context-path, and the default port would be 8080, means your application would be available at localhost:8080. But you can overwrite these properties by declaring them in application.yml [or application.yaml/application.properties] file. In our case, the first document [top level part, above '---' line] is the one configuring port and context path.
  • Since we will be using profiles, we have created two separate documents each with it’s own profile.
  • By default if no profile is specified, ‘default’ profile is used, this is standard spring behavior. You can additionally create different profiles based on your environments and use them on run.
  • In our case, we are pointing both default and local to same profile, hence letting user to run the app directly, without specifying any profile, in that case the default profile will be used. But you are free to specify a profile. While running our example [via IDE or command-line], we can provide the profile information using -Dspring.profiles.active=local or -Dspring.profiles.active=prod in VM arguments[for IDE] or on command-line java -jar JARPATH --spring.profiles.active=local.
  • Notice the datasource part in yml file: here we are specifying all stuff related to database. Similarly if you have other aspects/concerns [security e.g.], you could create separate levels for that. We will be using H2 database while running under profile ‘local’ and MySQL while running with profile ‘prod’.
In case you face trouble with YAML, Online YAML editor comes handy to validate your YAML.

5. Model

User.java

package com.websystique.springboot.model;

import org.hibernate.validator.constraints.NotEmpty;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name="APP_USER")
public class User implements Serializable{

	@Id
	@GeneratedValue(strategy= GenerationType.IDENTITY)
	private Long id;

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

	@Column(name="AGE", nullable=false)
	private Integer age;

	@Column(name="SALARY", nullable=false)
	private double salary;

--- getter/setter omitted to save space
}

6. Spring-Data repositories

This one is rather simple.

package com.websystique.springboot.repositories;

import com.websystique.springboot.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    User findByName(String name);

}

That’s it for spring-data part. Interface JpaRepository packs a punch. It provides all the CRUD operations by-default using id as the key. In case you need to lookup on a property other than id, you could just create a ‘camelCase’ signature with that property, spring-data will itself generate the implementation and execute the appropriate SQL to get the data out from database. spring-data @Query annotation goes a step further by allowing you to write the JPQL or even native SQL yourself instead of relying on spring-data to do that. One could as well extend from CrudRepository instead of JpaRepository but JpaRepository provides some goodies like paging and sorting which most of the time is needed in a FE application.

7. Service

Our controller will be using this service for all user-related operations. Service in turn uses our spring-data repository to access and update the user.

package com.websystique.springboot.service;

import com.websystique.springboot.model.User;
import java.util.List;

public interface UserService {
	
	User findById(Long id);

	User findByName(String name);

	void saveUser(User user);

	void updateUser(User user);

	void deleteUserById(Long id);

	void deleteAllUsers();

	List<User> findAllUsers();

	boolean isUserExist(User user);
}
package com.websystique.springboot.service;

import java.util.List;

import com.websystique.springboot.model.User;
import com.websystique.springboot.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;



@Service("userService")
@Transactional
public class UserServiceImpl implements UserService{

	@Autowired
	private UserRepository userRepository;

	public User findById(Long id) {
		return userRepository.findOne(id);
	}

	public User findByName(String name) {
		return userRepository.findByName(name);
	}

	public void saveUser(User user) {
		userRepository.save(user);
	}

	public void updateUser(User user){
		saveUser(user);
	}

	public void deleteUserById(Long id){
		userRepository.delete(id);
	}

	public void deleteAllUsers(){
		userRepository.deleteAll();
	}

	public List<User> findAllUsers(){
		return userRepository.findAll();
	}

	public boolean isUserExist(User user) {
		return findByName(user.getName()) != null;
	}

}

8. Controllers

We have two controllers in our application. One for handling the view and other for handling the REST API calls, coming from Our AngularJS based Front-end.

package com.websystique.springboot.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class AppController {

	@RequestMapping("/")
	String home(ModelMap modal) {
		modal.addAttribute("title","CRUD Example");
		return "index";
	}

	@RequestMapping("/partials/{page}")
	String partialHandler(@PathVariable("page") final String page) {
		return page;
	}

}

package com.websystique.springboot.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;

import com.websystique.springboot.model.User;
import com.websystique.springboot.service.UserService;
import com.websystique.springboot.util.CustomErrorType;

@RestController
@RequestMapping("/api")
public class RestApiController {

	public static final Logger logger = LoggerFactory.getLogger(RestApiController.class);

	@Autowired
	UserService userService; //Service which will do all data retrieval/manipulation work

	// -------------------Retrieve All Users---------------------------------------------

	@RequestMapping(value = "/user/", method = RequestMethod.GET)
	public ResponseEntity<List<User>> listAllUsers() {
		List<User> users = userService.findAllUsers();
		if (users.isEmpty()) {
			return new ResponseEntity(HttpStatus.NO_CONTENT);
			// You many decide to return HttpStatus.NOT_FOUND
		}
		return new ResponseEntity<List<User>>(users, HttpStatus.OK);
	}

	// -------------------Retrieve Single User------------------------------------------

	@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
	public ResponseEntity<?> getUser(@PathVariable("id") long id) {
		logger.info("Fetching User with id {}", id);
		User user = userService.findById(id);
		if (user == null) {
			logger.error("User with id {} not found.", id);
			return new ResponseEntity(new CustomErrorType("User with id " + id 
					+ " not found"), HttpStatus.NOT_FOUND);
		}
		return new ResponseEntity<User>(user, HttpStatus.OK);
	}

	// -------------------Create a User-------------------------------------------

	@RequestMapping(value = "/user/", method = RequestMethod.POST)
	public ResponseEntity<?> createUser(@RequestBody User user, UriComponentsBuilder ucBuilder) {
		logger.info("Creating User : {}", user);

		if (userService.isUserExist(user)) {
			logger.error("Unable to create. A User with name {} already exist", user.getName());
			return new ResponseEntity(new CustomErrorType("Unable to create. A User with name " + 
			user.getName() + " already exist."),HttpStatus.CONFLICT);
		}
		userService.saveUser(user);

		HttpHeaders headers = new HttpHeaders();
		headers.setLocation(ucBuilder.path("/api/user/{id}").buildAndExpand(user.getId()).toUri());
		return new ResponseEntity<String>(headers, HttpStatus.CREATED);
	}

	// ------------------- Update a User ------------------------------------------------

	@RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)
	public ResponseEntity<?> updateUser(@PathVariable("id") long id, @RequestBody User user) {
		logger.info("Updating User with id {}", id);

		User currentUser = userService.findById(id);

		if (currentUser == null) {
			logger.error("Unable to update. User with id {} not found.", id);
			return new ResponseEntity(new CustomErrorType("Unable to upate. User with id " + id + " not found."),
					HttpStatus.NOT_FOUND);
		}

		currentUser.setName(user.getName());
		currentUser.setAge(user.getAge());
		currentUser.setSalary(user.getSalary());

		userService.updateUser(currentUser);
		return new ResponseEntity<User>(currentUser, HttpStatus.OK);
	}

	// ------------------- Delete a User-----------------------------------------

	@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
	public ResponseEntity<?> deleteUser(@PathVariable("id") long id) {
		logger.info("Fetching & Deleting User with id {}", id);

		User user = userService.findById(id);
		if (user == null) {
			logger.error("Unable to delete. User with id {} not found.", id);
			return new ResponseEntity(new CustomErrorType("Unable to delete. User with id " + id + " not found."),
					HttpStatus.NOT_FOUND);
		}
		userService.deleteUserById(id);
		return new ResponseEntity<User>(HttpStatus.NO_CONTENT);
	}

	// ------------------- Delete All Users-----------------------------

	@RequestMapping(value = "/user/", method = RequestMethod.DELETE)
	public ResponseEntity<User> deleteAllUsers() {
		logger.info("Deleting All Users");

		userService.deleteAllUsers();
		return new ResponseEntity<User>(HttpStatus.NO_CONTENT);
	}

}

Additionally, a helper class to send errors [in-case any] from API in JSON format iso string.

package com.websystique.springboot.util;


public class CustomErrorType {

    private String errorMessage;

    public CustomErrorType(String errorMessage){
        this.errorMessage = errorMessage;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

}

Populate MySQL database

If you look back at application.yml, we have set the hibernate hbm2ddl as ‘create-drop‘ under ‘local’ profile, where as ‘update‘ under ‘prod’ profile, just for demonstration purpose. That mean in ‘local’ [H2], table will be dropped and recreated at application startup so we don’t need to create it manually. But in case of ‘prod’ [MySQL], we need to manually create the table if it does not exist. For MySQL, You can run following SQL to create table and populate dummy data.

create table APP_USER (
   id BIGINT NOT NULL AUTO_INCREMENT,
   name VARCHAR(30) NOT NULL,
   age  INTEGER NOT NULL,
   salary REAL NOT NULL,
   PRIMARY KEY (id)
);
  
/* Populate USER Table */
INSERT INTO APP_USER(name,age,salary)
VALUES ('Sam',30,70000);
  
INSERT INTO APP_USER(name,age,salary)
VALUES ('Tom',40,50000);

commit;

Front-end

Let’s add a view to our MVC app. We would be using Freemarker templates in our app. Spring Boot WebMvcAutoConfiguration adds FreeMarkerViewResolver with id ‘freeMarkerViewResolver’ if freemarker jar is in classpath, which is the case since we are using spring-boot-starter-freemarker. It looks for resources in a loader path (externalized to spring.freemarker.templateLoaderPath, default ‘classpath:/templates/’) by surrounding the view name with a prefix and suffix (externalized to spring.freemarker.prefix and spring.freemarker.suffix, with empty and ‘.ftl’ defaults respectively). It can be overridden by providing a bean of the same name.

Although one can develop a complete FE using freemarker itself with tons of scripts and cryptic expressions with ‘#’ lurking around all over the page, question is should we, knowing that we are not in 1990 anymore? I decided to use AngularJS [with ui-router] instead, using freemarker just as a container, nothing else.

Freemarker Templates

src/main/resources/templates/index.ftl

<!DOCTYPE html>

<html lang="en" ng-app="crudApp">
    <head>
        <title>${title}</title>
        <link href="css/bootstrap.css" rel="stylesheet"/>
        <link href="css/app.css" rel="stylesheet"/>
    </head>
    <body>

        <div ui-view></div>
        <script src="js/lib/angular.min.js" ></script>
        <script src="js/lib/angular-ui-router.min.js" ></script>
        <script src="js/lib/localforage.min.js" ></script>
        <script src="js/lib/ngStorage.min.js"></script>
        <script src="js/app/app.js"></script>
        <script src="js/app/UserService.js"></script>
        <script src="js/app/UserController.js"></script>
    </body>
</html>

src/main/resources/templates/list.ftl

<div class="generic-container">
    <div class="panel panel-default">
        <!-- Default panel contents -->
        <div class="panel-heading"><span class="lead">Specific User </span></div>
		<div class="panel-body">
	        <div class="formcontainer">
	            <div class="alert alert-success" role="alert" ng-if="ctrl.successMessage">{{ctrl.successMessage}}</div>
	            <div class="alert alert-danger" role="alert" ng-if="ctrl.errorMessage">{{ctrl.errorMessage}}</div>
	            <form ng-submit="ctrl.submit()" name="myForm" class="form-horizontal">
	                <input type="hidden" ng-model="ctrl.user.id" />
	                <div class="row">
	                    <div class="form-group col-md-12">
	                        <label class="col-md-2 control-lable" for="uname">Name</label>
	                        <div class="col-md-7">
	                            <input type="text" ng-model="ctrl.user.name" id="uname" class="username form-control input-sm" placeholder="Enter your name" required ng-minlength="3"/>
	                        </div>
	                    </div>
	                </div>

	                <div class="row">
	                    <div class="form-group col-md-12">
	                        <label class="col-md-2 control-lable" for="age">Age</label>
	                        <div class="col-md-7">
	                            <input type="text" ng-model="ctrl.user.age" id="age" class="form-control input-sm" placeholder="Enter your Age." required ng-pattern="ctrl.onlyIntegers"/>
	                        </div>
	                    </div>
	                </div>
	
	                <div class="row">
	                    <div class="form-group col-md-12">
	                        <label class="col-md-2 control-lable" for="salary">Salary</label>
	                        <div class="col-md-7">
	                            <input type="text" ng-model="ctrl.user.salary" id="salary" class="form-control input-sm" placeholder="Enter your Salary." required ng-pattern="ctrl.onlyNumbers"/>
	                        </div>
	                    </div>
	                </div>

	                <div class="row">
	                    <div class="form-actions floatRight">
	                        <input type="submit"  value="{{!ctrl.user.id ? 'Add' : 'Update'}}" class="btn btn-primary btn-sm" ng-disabled="myForm.$invalid || myForm.$pristine">
	                        <button type="button" ng-click="ctrl.reset()" class="btn btn-warning btn-sm" ng-disabled="myForm.$pristine">Reset Form</button>
	                    </div>
	                </div>
	            </form>
    	    </div>
		</div>	
    </div>
    <div class="panel panel-default">
        <!-- Default panel contents -->
        <div class="panel-heading"><span class="lead">List of Users </span></div>
		<div class="panel-body">
			<div class="table-responsive">
		        <table class="table table-hover">
		            <thead>
		            <tr>
		                <th>ID</th>
		                <th>NAME</th>
		                <th>AGE</th>
		                <th>SALARY</th>
		                <th width="100"></th>
		                <th width="100"></th>
		            </tr>
		            </thead>
		            <tbody>
		            <tr ng-repeat="u in ctrl.getAllUsers()">
		                <td>{{u.id}}</td>
		                <td>{{u.name}}</td>
		                <td>{{u.age}}</td>
		                <td>{{u.salary}}</td>
		                <td><button type="button" ng-click="ctrl.editUser(u.id)" class="btn btn-success custom-width">Edit</button></td>
		                <td><button type="button" ng-click="ctrl.removeUser(u.id)" class="btn btn-danger custom-width">Remove</button></td>
		            </tr>
		            </tbody>
		        </table>		
			</div>
		</div>
    </div>
</div>

Static resources

Static resources like images/css/JS in a Spring boot application are commonly located in a directory called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext. In this example, we are using bootstrap.css which is located in src/main/resources/static/css.

Error Page

By default, Spring Boot installs a ‘whitelabel’ error page that is shown in browser client if you encounter a server error. You can override that page, based upon the templating technology you are using. For freemarker, you can create a page with name ‘error.ftl’ which would be shown in case an error occurred.

src/main/resources/templates/error.ftl

<!DOCTYPE html>

<html lang="en">
<head>
    <link rel="stylesheet" type="text/css" href="css/bootstrap.css" />
</head>
<body>
	<div class="container">
	    <div class="jumbotron alert-danger">
			<h1>Oops. Something went wrong</h1>
			<h2>${status} ${error}</h2>
	    </div>
	</div>
</body>

</html>

AngularJs [ui-router based app]

src/main/resources/static/js/app.js

var app = angular.module('crudApp',['ui.router','ngStorage']);

app.constant('urls', {
    BASE: 'http://localhost:8080/SpringBootCRUDApp',
    USER_SERVICE_API : 'http://localhost:8080/SpringBootCRUDApp/api/user/'
});

app.config(['$stateProvider', '$urlRouterProvider',
    function($stateProvider, $urlRouterProvider) {

        $stateProvider
            .state('home', {
                url: '/',
                templateUrl: 'partials/list',
                controller:'UserController',
                controllerAs:'ctrl',
                resolve: {
                    users: function ($q, UserService) {
                        console.log('Load all users');
                        var deferred = $q.defer();
                        UserService.loadAllUsers().then(deferred.resolve, deferred.resolve);
                        return deferred.promise;
                    }
                }
            });
        $urlRouterProvider.otherwise('/');
    }]);

src/main/resources/static/js/UserService.js

'use strict';

angular.module('crudApp').factory('UserService',
    ['$localStorage', '$http', '$q', 'urls',
        function ($localStorage, $http, $q, urls) {

            var factory = {
                loadAllUsers: loadAllUsers,
                getAllUsers: getAllUsers,
                getUser: getUser,
                createUser: createUser,
                updateUser: updateUser,
                removeUser: removeUser
            };

            return factory;

            function loadAllUsers() {
                console.log('Fetching all users');
                var deferred = $q.defer();
                $http.get(urls.USER_SERVICE_API)
                    .then(
                        function (response) {
                            console.log('Fetched successfully all users');
                            $localStorage.users = response.data;
                            deferred.resolve(response);
                        },
                        function (errResponse) {
                            console.error('Error while loading users');
                            deferred.reject(errResponse);
                        }
                    );
                return deferred.promise;
            }

            function getAllUsers(){
                return $localStorage.users;
            }

            function getUser(id) {
                console.log('Fetching User with id :'+id);
                var deferred = $q.defer();
                $http.get(urls.USER_SERVICE_API + id)
                    .then(
                        function (response) {
                            console.log('Fetched successfully User with id :'+id);
                            deferred.resolve(response.data);
                        },
                        function (errResponse) {
                            console.error('Error while loading user with id :'+id);
                            deferred.reject(errResponse);
                        }
                    );
                return deferred.promise;
            }

            function createUser(user) {
                console.log('Creating User');
                var deferred = $q.defer();
                $http.post(urls.USER_SERVICE_API, user)
                    .then(
                        function (response) {
                            loadAllUsers();
                            deferred.resolve(response.data);
                        },
                        function (errResponse) {
                           console.error('Error while creating User : '+errResponse.data.errorMessage);
                           deferred.reject(errResponse);
                        }
                    );
                return deferred.promise;
            }

            function updateUser(user, id) {
                console.log('Updating User with id '+id);
                var deferred = $q.defer();
                $http.put(urls.USER_SERVICE_API + id, user)
                    .then(
                        function (response) {
                            loadAllUsers();
                            deferred.resolve(response.data);
                        },
                        function (errResponse) {
                            console.error('Error while updating User with id :'+id);
                            deferred.reject(errResponse);
                        }
                    );
                return deferred.promise;
            }

            function removeUser(id) {
                console.log('Removing User with id '+id);
                var deferred = $q.defer();
                $http.delete(urls.USER_SERVICE_API + id)
                    .then(
                        function (response) {
                            loadAllUsers();
                            deferred.resolve(response.data);
                        },
                        function (errResponse) {
                            console.error('Error while removing User with id :'+id);
                            deferred.reject(errResponse);
                        }
                    );
                return deferred.promise;
            }

        }
    ]);

src/main/resources/static/js/UserController.js

'use strict';

angular.module('crudApp').controller('UserController',
    ['UserService', '$scope',  function( UserService, $scope) {

        var self = this;
        self.user = {};
        self.users=[];

        self.submit = submit;
        self.getAllUsers = getAllUsers;
        self.createUser = createUser;
        self.updateUser = updateUser;
        self.removeUser = removeUser;
        self.editUser = editUser;
        self.reset = reset;

        self.successMessage = '';
        self.errorMessage = '';
        self.done = false;

        self.onlyIntegers = /^\d+$/;
        self.onlyNumbers = /^\d+([,.]\d+)?$/;

        function submit() {
            console.log('Submitting');
            if (self.user.id === undefined || self.user.id === null) {
                console.log('Saving New User', self.user);
                createUser(self.user);
            } else {
                updateUser(self.user, self.user.id);
                console.log('User updated with id ', self.user.id);
            }
        }

        function createUser(user) {
            console.log('About to create user');
            UserService.createUser(user)
                .then(
                    function (response) {
                        console.log('User created successfully');
                        self.successMessage = 'User created successfully';
                        self.errorMessage='';
                        self.done = true;
                        self.user={};
                        $scope.myForm.$setPristine();
                    },
                    function (errResponse) {
                        console.error('Error while creating User');
                        self.errorMessage = 'Error while creating User: ' + errResponse.data.errorMessage;
                        self.successMessage='';
                    }
                );
        }


        function updateUser(user, id){
            console.log('About to update user');
            UserService.updateUser(user, id)
                .then(
                    function (response){
                        console.log('User updated successfully');
                        self.successMessage='User updated successfully';
                        self.errorMessage='';
                        self.done = true;
                        $scope.myForm.$setPristine();
                    },
                    function(errResponse){
                        console.error('Error while updating User');
                        self.errorMessage='Error while updating User '+errResponse.data;
                        self.successMessage='';
                    }
                );
        }


        function removeUser(id){
            console.log('About to remove User with id '+id);
            UserService.removeUser(id)
                .then(
                    function(){
                        console.log('User '+id + ' removed successfully');
                    },
                    function(errResponse){
                        console.error('Error while removing user '+id +', Error :'+errResponse.data);
                    }
                );
        }


        function getAllUsers(){
            return UserService.getAllUsers();
        }

        function editUser(id) {
            self.successMessage='';
            self.errorMessage='';
            UserService.getUser(id).then(
                function (user) {
                    self.user = user;
                },
                function (errResponse) {
                    console.error('Error while removing user ' + id + ', Error :' + errResponse.data);
                }
            );
        }
        function reset(){
            self.successMessage='';
            self.errorMessage='';
            self.user={};
            $scope.myForm.$setPristine(); //reset Form
        }
    }
    ]);

Run the application

Finally, Let’s run the application, firstly with ‘local’ profile [H2]. Next shot will be with ‘prod’ profile [MySQL].

Via Eclipse:: Run it directly, in that case default profile will be used. In case you want a different profile to be used, create a Run configuration for you main class, specifying the profile. To do that from toolbar, select Run->Run Configurations->Arguments->VM Arguments. Add -Dspring.profiles.active=local or -Dspring.profiles.active=prod]

Via Command line::
On project root
$> java -jar target/SpringBootCRUDApplicationExample-1.0.0.jar –spring.profiles.active=local

Please take special note of two ‘-’ in front of spring.profiles.active. In the blog it might be appearing as single ‘-’ but there are in fact two ‘-’ of them.


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.3.RELEASE)

2016-12-26 17:15:35.114  INFO 4496 --- [           main] c.w.springboot.SpringBootCRUDApp         : Starting SpringBootCRUDApp on dragon with PID 4496 (D:\Development\workspaces\workspace_websystique\SpringBootCRUDApplicationExample\target\classes started by ADMIN in D:\Development\workspaces\workspace_websystique\SpringBootCRUDApplicationExample)
2016-12-26 17:15:35.121  INFO 4496 --- [           main] c.w.springboot.SpringBootCRUDApp         : The following profiles are active: local
2016-12-26 17:15:35.225  INFO 4496 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@45b4c3a9: startup date [Mon Dec 26 17:15:35 CET 2016]; root of context hierarchy
2016-12-26 17:15:38.422  INFO 4496 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [class org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$e0f3dd92] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2016-12-26 17:15:39.458  INFO 4496 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2016-12-26 17:15:39.484  INFO 4496 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2016-12-26 17:15:39.486  INFO 4496 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.6
2016-12-26 17:15:39.692  INFO 4496 --- [ost-startStop-1] o.a.c.c.C.[.[.[/SpringBootCRUDApp]       : Initializing Spring embedded WebApplicationContext
2016-12-26 17:15:39.693  INFO 4496 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 4474 ms
2016-12-26 17:15:40.031  INFO 4496 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2016-12-26 17:15:40.037  INFO 4496 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2016-12-26 17:15:40.038  INFO 4496 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2016-12-26 17:15:40.038  INFO 4496 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2016-12-26 17:15:40.038  INFO 4496 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2016-12-26 17:15:40.334  INFO 4496 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2016-12-26 17:15:40.360  INFO 4496 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
	name: default
	...]
2016-12-26 17:15:40.488  INFO 4496 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.0.11.Final}
2016-12-26 17:15:40.490  INFO 4496 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2016-12-26 17:15:40.492  INFO 4496 --- [           main] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
2016-12-26 17:15:40.569  INFO 4496 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2016-12-26 17:15:40.786  INFO 4496 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Started.
2016-12-26 17:15:41.228  INFO 4496 --- [           main] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Driver does not support get/set network timeout for connections. (org.h2.jdbc.JdbcConnection.getNetworkTimeout()I)
2016-12-26 17:15:41.311  INFO 4496 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2016-12-26 17:15:41.908  INFO 4496 --- [           main] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000227: Running hbm2ddl schema export
Hibernate: 
    drop table APP_USER if exists
Hibernate: 
    create table APP_USER (
        id bigint generated by default as identity,
        AGE integer not null,
        NAME varchar(255) not null,
        SALARY double not null,
        primary key (id)
    )
2016-12-26 17:15:41.927  INFO 4496 --- [           main] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000230: Schema export complete
2016-12-26 17:15:41.987  INFO 4496 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2016-12-26 17:15:42.983  INFO 4496 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@45b4c3a9: startup date [Mon Dec 26 17:15:35 CET 2016]; root of context hierarchy
2016-12-26 17:15:43.109  INFO 4496 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto java.lang.String com.websystique.springboot.controller.AppController.home(org.springframework.ui.ModelMap)
2016-12-26 17:15:43.110  INFO 4496 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/partials/{page}]}" onto java.lang.String com.websystique.springboot.controller.AppController.partialHandler(java.lang.String)
2016-12-26 17:15:43.116  INFO 4496 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/user/{id}],methods=[GET]}" onto public org.springframework.http.ResponseEntity<?> com.websystique.springboot.controller.RestApiController.getUser(long)
2016-12-26 17:15:43.117  INFO 4496 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/user/],methods=[GET]}" onto public org.springframework.http.ResponseEntity<java.util.List<com.websystique.springboot.model.User>> com.websystique.springboot.controller.RestApiController.listAllUsers()
2016-12-26 17:15:43.117  INFO 4496 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/user/],methods=[POST]}" onto public org.springframework.http.ResponseEntity<?> com.websystique.springboot.controller.RestApiController.createUser(com.websystique.springboot.model.User,org.springframework.web.util.UriComponentsBuilder)
2016-12-26 17:15:43.117  INFO 4496 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/user/{id}],methods=[PUT]}" onto public org.springframework.http.ResponseEntity<?> com.websystique.springboot.controller.RestApiController.updateUser(long,com.websystique.springboot.model.User)
2016-12-26 17:15:43.118  INFO 4496 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/user/{id}],methods=[DELETE]}" onto public org.springframework.http.ResponseEntity<?> com.websystique.springboot.controller.RestApiController.deleteUser(long)
2016-12-26 17:15:43.118  INFO 4496 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/user/],methods=[DELETE]}" onto public org.springframework.http.ResponseEntity<com.websystique.springboot.model.User> com.websystique.springboot.controller.RestApiController.deleteAllUsers()
2016-12-26 17:15:43.122  INFO 4496 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2016-12-26 17:15:43.123  INFO 4496 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=1}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2016-12-26 17:15:43.185  INFO 4496 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-12-26 17:15:43.185  INFO 4496 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-12-26 17:15:43.261  INFO 4496 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-12-26 17:15:43.708  INFO 4496 --- [           main] o.s.w.s.v.f.FreeMarkerConfigurer         : ClassTemplateLoader for Spring macros added to FreeMarker configuration
2016-12-26 17:15:44.002  INFO 4496 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2016-12-26 17:15:44.004  INFO 4496 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Bean with name 'dataSource' has been autodetected for JMX exposure
2016-12-26 17:15:44.014  INFO 4496 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located MBean 'dataSource': registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource]
2016-12-26 17:15:44.102  INFO 4496 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2016-12-26 17:15:44.110  INFO 4496 --- [           main] c.w.springboot.SpringBootCRUDApp         : Started SpringBootCRUDApp in 9.731 seconds (JVM running for 10.325)

Open your browser and navigate to http://localhost:8080/SpringBootCRUDApp/

springbootcrudapp_img1

Add few users.

springbootcrudapp_img2

Try to add a user with same name as an existing user, should get an error [this is backend throwing the error, you can change the logic on backend based on your business rules].

springbootcrudapp_img3

Reset the form.Remove a user, edit the other one.

springbootcrudapp_img4

Now shutdown your app and restart it using ‘prod’ profile this time.


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.4.3.RELEASE)

2016-12-26 18:58:18.947  INFO 6828 --- [           main] c.w.springboot.SpringBootCRUDApp         : Starting SpringBootCRUDApp on dragon with PID 6828 (D:\Development\workspaces\workspace_websystique\SpringBootCRUDApplicationExample\target\classes started by ADMIN in D:\Development\workspaces\workspace_websystique\SpringBootCRUDApplicationExample)
2016-12-26 18:58:18.952  INFO 6828 --- [           main] c.w.springboot.SpringBootCRUDApp         : The following profiles are active: prod
2016-12-26 18:58:19.073  INFO 6828 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@45b4c3a9: startup date [Mon Dec 26 18:58:19 CET 2016]; root of context hierarchy
2016-12-26 18:58:21.827  INFO 6828 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [class org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$e0f3dd92] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2016-12-26 18:58:22.808  INFO 6828 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2016-12-26 18:58:22.833  INFO 6828 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2016-12-26 18:58:22.835  INFO 6828 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.6
2016-12-26 18:58:23.052  INFO 6828 --- [ost-startStop-1] o.a.c.c.C.[.[.[/SpringBootCRUDApp]       : Initializing Spring embedded WebApplicationContext
2016-12-26 18:58:23.053  INFO 6828 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3986 ms
2016-12-26 18:58:23.386  INFO 6828 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2016-12-26 18:58:23.395  INFO 6828 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2016-12-26 18:58:23.396  INFO 6828 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2016-12-26 18:58:23.397  INFO 6828 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2016-12-26 18:58:23.397  INFO 6828 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2016-12-26 18:58:23.640  INFO 6828 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2016-12-26 18:58:23.675  INFO 6828 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
	name: default
	...]
2016-12-26 18:58:23.823  INFO 6828 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.0.11.Final}
2016-12-26 18:58:23.826  INFO 6828 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2016-12-26 18:58:23.830  INFO 6828 --- [           main] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
2016-12-26 18:58:23.912  INFO 6828 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2016-12-26 18:58:24.110  INFO 6828 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Started.
2016-12-26 18:58:24.823  INFO 6828 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
2016-12-26 18:58:25.607  INFO 6828 --- [           main] org.hibernate.tool.hbm2ddl.SchemaUpdate  : HHH000228: Running hbm2ddl schema update
2016-12-26 18:58:25.774  INFO 6828 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2016-12-26 18:58:26.707  INFO 6828 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@45b4c3a9: startup date [Mon Dec 26 18:58:19 CET 2016]; root of context hierarchy
2016-12-26 18:58:26.833  INFO 6828 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto java.lang.String com.websystique.springboot.controller.AppController.home(org.springframework.ui.ModelMap)
2016-12-26 18:58:26.835  INFO 6828 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/partials/{page}]}" onto java.lang.String com.websystique.springboot.controller.AppController.partialHandler(java.lang.String)
2016-12-26 18:58:26.840  INFO 6828 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/user/],methods=[GET]}" onto public org.springframework.http.ResponseEntity<java.util.List<com.websystique.springboot.model.User>> com.websystique.springboot.controller.RestApiController.listAllUsers()
2016-12-26 18:58:26.841  INFO 6828 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/user/{id}],methods=[GET]}" onto public org.springframework.http.ResponseEntity<?> com.websystique.springboot.controller.RestApiController.getUser(long)
2016-12-26 18:58:26.841  INFO 6828 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/user/],methods=[POST]}" onto public org.springframework.http.ResponseEntity<?> com.websystique.springboot.controller.RestApiController.createUser(com.websystique.springboot.model.User,org.springframework.web.util.UriComponentsBuilder)
2016-12-26 18:58:26.842  INFO 6828 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/user/{id}],methods=[PUT]}" onto public org.springframework.http.ResponseEntity<?> com.websystique.springboot.controller.RestApiController.updateUser(long,com.websystique.springboot.model.User)
2016-12-26 18:58:26.842  INFO 6828 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/user/{id}],methods=[DELETE]}" onto public org.springframework.http.ResponseEntity<?> com.websystique.springboot.controller.RestApiController.deleteUser(long)
2016-12-26 18:58:26.842  INFO 6828 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/user/],methods=[DELETE]}" onto public org.springframework.http.ResponseEntity<com.websystique.springboot.model.User> com.websystique.springboot.controller.RestApiController.deleteAllUsers()
2016-12-26 18:58:26.846  INFO 6828 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2016-12-26 18:58:26.847  INFO 6828 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=1}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2016-12-26 18:58:26.903  INFO 6828 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-12-26 18:58:26.904  INFO 6828 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-12-26 18:58:27.008  INFO 6828 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-12-26 18:58:27.363  INFO 6828 --- [           main] o.s.w.s.v.f.FreeMarkerConfigurer         : ClassTemplateLoader for Spring macros added to FreeMarker configuration
2016-12-26 18:58:27.604  INFO 6828 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2016-12-26 18:58:27.606  INFO 6828 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Bean with name 'dataSource' has been autodetected for JMX exposure
2016-12-26 18:58:27.614  INFO 6828 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located MBean 'dataSource': registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource]
2016-12-26 18:58:27.711  INFO 6828 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2016-12-26 18:58:27.720  INFO 6828 --- [           main] c.w.springboot.SpringBootCRUDApp         : Started SpringBootCRUDApp in 9.478 seconds (JVM running for 10.023)

Provided your mysql is up and running, you should get following, right from MySQL database this time :

springbootcrudapp_img5

Conclusion

Although the post was bit long, Spring Boot and associated concepts are fairly trivial. Spring Boot reduces the development time by many-fold, worth giving a try. The application we developed here is fully loaded and can be used in a live environment or as the base application for your own projects. Feel free to write your thoughts in comment section.

Download Source Code



References

If you like tutorials on this site, why not take a step further and connect me on Facebook , Google Plus & Twitter as well? I would love to hear your thoughts on these articles, it will help me improve further our learning process.

If you appreciate the effort I have put in this learning site, help me improve the visibility of this site towards global audience by sharing and linking this site from within and beyond your network. You & your friends can always link my site from your site on www.websystique.com, and share the learning.

After all, we are here to learn together, aren’t we?

  • techsavvy

    Hi
    I got this error
    HTTP Status 404 – /SpringBootCRUDApplicationExample/

    my .yml file is as below

    server:
    port: 8080
    contextPath: /SpringBootCRUDApp

    spring:
    profiles: local, default
    datasource:
    sampleapp:
    url: jdbc:h2:~/emp
    username: root
    password: root
    driverClassName: org.h2.Driver
    defaultSchema:
    maxPoolSize: 10
    hibernate:
    hbm2ddl.method: create-drop
    show_sql: true
    format_sql: true
    dialect: org.hibernate.dialect.H2Dialect

    spring:
    profiles: prod
    datasource:
    sampleapp:
    url: jdbc:mysql://localhost:3306/emp
    username: root
    password: root
    driverClassName: com.mysql.jdbc.Driver
    defaultSchema:
    maxPoolSize: 20
    hibernate:
    hbm2ddl.method: update
    show_sql: true
    format_sql: true
    dialect: org.hibernate.dialect.MySQLDialect

    I have one warning
    WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property ‘source’ to ‘org.eclipse.jst.jee.server:SpringBootCRUDApplicationExample’ did not find a matching property.

    Can you please help me on this
    I am using eclipse oxygen I dont have h2 installed on my machine.

    • techsavvy

      also installed h2 but still not working

  • https://javacodepoint.com Ravi kumar

    You can use apache tomacat 9 with eclipse. i have deployed and working fine at sts eclipse.
    update your maven to know more.. i had updated on https://javacodepoint.com

  • martin s

    Hello am getting this error
    [ERROR] Failed to execute goal org.apache.tomcat.maven:tomcat7-maven-plugin:2.2:run (default-cli) on project Spring4MVCAngularJSExample: Could not start Tomcat: Failed to start component [StandardServer[-1]]: Failed to start component [StandardService[Tomcat]]: Failed to start component [StandardEngine[Tomcat]]: A child container failed during start -> [Help 1]

  • Anish Panthi

    I’m getting error. I downloaded source code and tried to run after changing database configuration in application.yml.
    2017-07-06 21:14:40.592 WARN 15540 — [ main] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization – cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration’: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘javax.sql.DataSource’ available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
    2017-07-06 21:14:40.595 INFO 15540 — [ main] o.apache.catalina.core.StandardService : Stopping service Tomcat
    2017-07-06 21:14:40.707 WARN 15540 — [ost-startStop-1] o.a.c.loader.WebappClassLoaderBase : The web application [UserManagementBoot] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
    java.lang.Object.wait(Native Method)
    java.lang.ref.ReferenceQueue.remove(Unknown Source)
    com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:43)
    2017-07-06 21:14:40.717 INFO 15540 — [ main] utoConfigurationReportLoggingInitializer :

    Error starting ApplicationContext. To display the auto-configuration report re-run your application with ‘debug’ enabled.
    2017-07-06 21:14:40.910 ERROR 15540 — [ main] o.s.b.d.LoggingFailureAnalysisReporter :

    ***************************
    APPLICATION FAILED TO START
    ***************************

    Description:

    Parameter 0 of constructor in org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration required a bean of type ‘javax.sql.DataSource’ that could not be found.
    - Bean method ‘dataSource’ not loaded because @ConditionalOnProperty (spring.datasource.jndi-name) did not find property ‘jndi-name’
    - Bean method ‘dataSource’ not loaded because @ConditionalOnBean (types: org.springframework.boot.jta.XADataSourceWrapper; SearchStrategy: all) did not find any beans

    Action:

    Consider revisiting the conditions above or defining a bean of type ‘javax.sql.DataSource’ in your configuration.

  • https://javacodepoint.com Ravi kumar

    Nice example. love it.

    to know more.. https://javacodepoint.com

  • Pingback: Hibernate Many-To-Many Unidirectional ( Annotation) - WebSystique()

  • Pingback: Hibernate One-To-One Bidirectional with Shared Primary Key (Annotation) - WebSystique()

  • Pingback: Hibernate MySQL Maven Hello World Example (Annotation) - WebSystique()

  • Pingback: Spring Batch- Read From MySQL database & write to CSV file - WebSystique()

  • Pingback: Spring Security 4 Role Based Login Example - WebSystique()

  • Pingback: Spring MVC 4 + Spring Security 4 + Hibernate Example - WebSystique()

  • Pingback: AngularJS+Spring Security using Basic Authentication - WebSystique()

  • Pingback: Spring 4 MVC+Hibernate Many-to-many JSP Example with annotation - WebSystique()

  • Pingback: Spring 4 MVC+Hibernate 4+MySQL+Maven integration example using annotations - WebSystique()

  • Pawan

    Getting an error after importing the project in the IDE. Error in main class in getting the .class file

  • Irfan Nasim

    Did not get any Jar file in target folder.

  • http://www.tourismism.com Savan Javia

    HI
    I am getting a this type of error
    Error: Could not find or load main class com.websystique.springboot.SpringBootCRUDApp

  • Pingback: Aplicação spring boot + angularjs + mysql e fonte do app | repositorio de links()

  • Pingback: Aplicação spring boot + angularjs + mysql e fonte do app – projetotajmahal()

  • http://about.me/malomakholofelo/ kholofelo Maloma

    One thing I appreciate the most is the effort you have made to provide such great knowledge for free! Thank you so much.

  • Jesse Zhou

    Wow this is a very nice tutorial, I can’t believe it required so much classes and stuff to get one single page lol. I would have to go back and understand all the functionalities. More details on what is going with the javascript files please.

  • Mark

    Dear websystique,

    Thank you very much for this tutorial.
    Since I have Jenkins running on port 8080, I changed the port in application.yml to 8081.
    I found out that I had to change also the port number in app.js

    ——————————–
    app.constant(‘urls’, {
    BASE: ‘http://localhost:8081/SpringBootCRUDApp’,
    USER_SERVICE_API : ‘http://localhost:8081/SpringBootCRUDApp/api/user/’
    });
    ——————————-

    It is not a good practice that you have to change the url and port number in two places. It is better to change the thUserService.js as I demonstrate below

    function loadAllUsers() {
    console.log(‘Fetching all users’);
    var deferred = $q.defer();

    var getUrl = window.location;
    var baseUrl = getUrl .protocol + “//” + getUrl.host + “/” + getUrl.pathname.split(‘/’)[1];
    var USER_SERVICE_API_NEW = baseUrl + “/api/user/”;
    $http.get(USER_SERVICE_API_NEW)
    .then(

    function getUser(id) {
    console.log(‘Fetching User with id :’+id);
    var deferred = $q.defer();

    var getUrl = window.location;
    var baseUrl = getUrl .protocol + “//” + getUrl.host + “/” + getUrl.pathname.split(‘/’)[1];
    var USER_SERVICE_API_NEW = baseUrl + “/api/user/”;
    // $http.get(urls.USER_SERVICE_API + id)
    $http.get(USER_SERVICE_API_NEW + id)
    .then(

    function createUser(user) {
    console.log(‘Creating User’);
    var deferred = $q.defer();
    var getUrl = window.location;
    var baseUrl = getUrl .protocol + “//” + getUrl.host + “/” + getUrl.pathname.split(‘/’)[1];
    var USER_SERVICE_API_NEW = baseUrl + “/api/user/”;
    // $http.post(urls.USER_SERVICE_API, user)
    $http.post(USER_SERVICE_API_NEW, user)
    .then(

    function updateUser(user, id) {
    console.log(‘Updating User with id ‘+id);
    var deferred = $q.defer();
    var getUrl = window.location;
    var baseUrl = getUrl .protocol + “//” + getUrl.host + “/” + getUrl.pathname.split(‘/’)[1];
    var USER_SERVICE_API_NEW = baseUrl + “/api/user/”;
    // $http.put(urls.USER_SERVICE_API + id, user)
    $http.put(USER_SERVICE_API_NEW + id, user)
    .then(

    function removeUser(id) {
    console.log(‘Removing User with id ‘+id);
    var deferred = $q.defer();

    var getUrl = window.location;
    var baseUrl = getUrl .protocol + “//” + getUrl.host + “/” + getUrl.pathname.split(‘/’)[1];
    var USER_SERVICE_API_NEW = baseUrl + “/api/user/”;
    // $http.delete(urls.USER_SERVICE_API + id)
    $http.delete(USER_SERVICE_API_NEW + id)
    .then(

    Furthermore I changed the file SpringBootCRUDApp.java, so that the application works also when
    no argument is provided for the application

    public class SpringBootCRUDApp {

    public static void main(String[] args) {

    if (args.length == 0) {
    args = new String[1];
    args[0] = “–spring.profiles.active=local”;
    }

    SpringApplication.run(SpringBootCRUDApp.class, args);
    }
    }

    Mark

  • administras

    nice tutorial, but you dont give any directions how to deal with js dependencies. Couple sentences would be nice.

  • federico_roma

    Hi, it’s really a great tutorial.
    I have a question, the application runs smoothly, all CRUD operations work, but I noticed that it actually does not read / write database information, it looks like it runs locally, I used Postgres.
    Thanks so much!

    • Roberto Londei

      Maybe you are running your application on H2, in this case you won’t see any changes on the Database.

  • Mrinmoy Majumdar

    Nice tutorial

  • Alik Elzin

    Great tutorial on how to pull everything together. Thanks.
    I have a suggestion. Drop the conversion to in the `updateUser` service. Instead just do:
    // currentUser.setName(user.getName());
    // currentUser.setAge(user.getAge());
    // currentUser.setSalary(user.getSalary());
    userService.updateUser(user);

  • Mrinmoy Majumdar

    This one is a more complete example on github: https://github.com/mrin9/Angular-SpringBoot-REST-JWT
    Have Spring security, JWT, JPA, H2 database and on angular side it has lazy loading of large datasets, visualization, routing, secured and unsecured routes etc

  • Tran Thang

    How can you enable H2-console ?
    I cannot access (http://localhost:8080/h2-console/) when I made this change in the application.yml as following:
    spring:
    profiles: local, default
    platform: h2
    h2:
    console:
    enabled: true
    path: /h2-console
    settings:
    web-allow-others: true

  • ditsikts

    Why not using gradle? isn’t better?

    • Ertogrul Selimli

      Gradle is not widely used ,maven is more popular

  • bmi

    Hello, I’m trying to make this progam work but so far with no success, I get this error : java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
    I have noticed dataSourceProperties is empty that is why the methods fails to add dataSourceClasName and other properties in Hikari Pool. I suspect my DataSourceProperties class can’t read my application.yml, my question is how can I make DataSourceProperties load conf stored in application.yml ? , I thought the problem was the choice of profile but I tried both options proposed in section 4 without success, Is there any hint on what might be my problem ??

    • websystique

      Hi, It seems that application.yml’s are not getting read properly. I wonder if you made any modifications in .yml which could have caused a special character/white space. YML’s are rather picky on that note. Could you please validate your .yml using online tool i mentioned in the post?

      • bmi

        I had already validated it, that was not the problem, actually, my solution was to remove default before in the dev profile(with H2),I dont know if it is normal,but to me it seems it didn’t support the profile to be at the same time local and default

    • Mrinmoy Majumdar

      This one is a more complete and working example on github: https://github.com/mrin9/Angular-SpringBoot-REST-JWT

  • zaghdoudi sofiene

    Hi,
    I’m a newbe in angular js, can any one explain me why we defined another deffered variable here ?

    resolve: {
    users: function ($q, UserService) {
    console.log(‘Load all users’);
    var deferred = $q.defer();
    UserService.loadAllUsers().then(deferred.resolve, deferred.resolve);
    return deferred.promise;
    }
    }

    why don’t return directly the promise of UserService.loadAllUsers() method , what we mean by the instruction UserService.loadAllUsers().then(deferred.resolve, deferred.resolve); ?

    • websystique

      Hi,
      ‘then’ function is providing you an opportunity to call special success or error handler when promise is resolved/rejected.

      You may want to right is as follows [to be explicit about success/error handling]:

      resolve: {
      users: function ($q, UserService) {
      console.log(‘Load all users’);
      var deferred = $q.defer();
      UserService.loadAllUsers().then(deferred.resolve, deferred.reject);
      return deferred.promise;
      }
      }

      • zaghdoudi sofiene

        Hi
        So why when i change the code like this (i have removed the deferred variable), the example still working :

        resolve : {
        users : function($q, UserService){
        return UserService.loadAllUsers();
        }
        }

        • websystique

          Hi, the point here is not that it still works, it is rather what it is made for. You can specify success and error handler here which could decide the future flow.

  • facilus

    Thank’s a lot of for this example.

    I’ve this error when i run the app :

    java.lang.IllegalStateException: required key [datasource.sampleapp.hibernate.dialect] not found

    • websystique

      Hi, have a look at point 4 above, there i specially mentioned to use — while running on command line.It seems you are facing the same problem.

    • Mrinmoy Majumdar

      This one is a better example on github for springboot and angular combo https://github.com/mrin9/Angular-SpringBoot-REST-JWT

  • Vikas Katiyar

    Hi ,
    I am unable deploy in tomcat 7 server pls help me..

    • websystique

      Hello Vikas, the procedure is exactly same for tomcat 7/8. I wonder if there is any other issue.Did you get exception?

    • Mrinmoy Majumdar

      try this example on github, it bundles the tomcat withing https://github.com/mrin9/Angular-SpringBoot-REST-JWT

  • bmi

    Hi, Thanks a lot for this tutorial, I have tried to follow your tutorial, but whenever I try to run it I get
    Error creating bean with name ‘entityManagerFactory’ defined in class path resource [com/testProject/configuration/JpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean]: Factory method ‘entityManagerFactory’ threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘dataSource’ defined in class path resource [com/testProject/configuration/JpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method ‘dataSource’ threw exception; nested exception is java.lang.IllegalArgumentException: maxPoolSize cannot be less than 1

    When I look at my application.yml the maxPoolSize is 10, I don’t understand why does it give me this error( am using eclipse). Thanks in advance for your help.

    • bmi

      @websystique:disqus any hint on the problem ??

  • Hamster151

    Hi, i have a question, why do you define interface UserService? Isn’t it redundant in this example? Why won’t you just create UserService as an concrete class?

    • websystique

      Hi, Coding to interfaces is a Best Practice which helps if used consistently.One can of course use a concrete class.

  • Roberto Londei

    Two question:

    1) Is there a way, within the code, to distinguish between “prod” and “local” profile?

    2) Is it possible to run JunitTest class automatically within mvn package call?

    • websystique

      Hi, sorry i missed it.

      2) For that you just need to adapt ‘hbm2ddl.method’ in yml

      hibernate:
      hbm2ddl.method: create-drop
      show_sql: true
      format_sql: true
      dialect: org.hibernate.dialect.MySQLDialect

      3) It is possible but why would you do that? And if you have to do that why would you want to do that in Java?

      • Roberto Londei

        @wesistique

        Why I want to delete Tables from java code?

        I created a PyUnitTest class, testing the backend, those test initialize the database at beginning of the test whit some constant test data, where the ID is the only element which is not initialized, because I configured Hibernate to automatically set the ID.
        Those data is supposed to always receive same ID from hibernate at first instance, at the end of the test I do clean up test data.
        When I run the test once, than shut down the backend, there is no problem, because the H2 data in cache will be automatically delete, and when I start the backend again and re-run the test everything is fine.
        PROBLEM: when I re-run the test without shutting down the backend, the data will be stored with ID sequentially determined starting from the last data stored in H2, even if all elements has being previously deleted. So in this case I do test against a slightly different version of the test data which was in the previous run, this is not that bad but still an issue.
        I would be perfect if I could be able to do the same operation which H2 does when shutting down the server, deleting all the tables and maybe also reinitializing / resetting the tables.
        Do you know if it is possible?

        Thanks

    • bmi

      @robertolondei:disqus Hello, am interested in your way of distinguishing profiles , however, I haven’t understood it, how does it help?, does it mean with that we don’t need to define the profile on Run as configuration VM (-Dspring.profiles.active=local or –spring.profiles.active=local), In general, I would like to know how is it useful. Thanks in advance.

      • Roberto Londei

        @bmi

        Hello,

        NO! You need to set the Profile Flag on application run, into the code you are then able to read which Profile configuration is the application running on, why do I do that?

        when running on local profile the Database Storage is a Fake Working Memory storage H2, H2 does not have all the functions a classical DB like MySQL has, as example the function DATE(someDate) which in case of local profile (== H2) I have to change through PARSEDATETIME(FORMATDATETIME(someDate,’yyyy-MM-dd’)). That’s is the main reason of distinguish the profiles.

        Hope you understand!
        Greetings

        @wesistique

        Why I want to delete Tables from java code?

        I created a PyUnitTest class, testing the backend, those test initialize the database at beginning of the test whit some constant test data, where the ID is the only element which is not initialized, because I configured Hibernate to automatically set the ID.
        Those data is supposed to always receive same ID from hibernate at first instance, at the end of the test I do clean up test data.
        When I run the test once, than shut down the backend, there is no problem, because the H2 data in cache will be automatically delete, and when I start the backend again and re-run the test everything is fine.
        PROBLEM: when I re-run the test without shutting down the backend, the data will be stored with ID sequentially determined starting from the last data stored in H2, even if all elements has being previously deleted. So in this case I do test against a slightly different version of the test data which was in the previous run, this is not that bad but still an issue.
        I would be perfect if I could be able to do the same operation which H2 does when shutting down the server, deleting all the tables and maybe also reinitializing / resetting the tables.
        Do you know if it is possible?

        Thanks

  • Pingback: Hibernate Many-To-One Bidirectional (Annotation) - WebSystique()

  • Pingback: Hibernate One-To-One Unidirectional with Shared Primary Key (Annotation) - WebSystique()

  • Pingback: Hibernate MySQL Maven Hello World Example (XML) - WebSystique()

  • Pingback: Spring Security 4 Method security using @PreAuthorize,@PostAuthorize, @Secured, EL - WebSystique()

  • Pingback: Spring Security 4 Hibernate Role Based Login Example - WebSystique()

  • Pingback: Spring Security 4 Hello World Annotation+XML Example - WebSystique()

  • Pingback: Spring 4 MVC REST Service Example using @RestController - WebSystique()

  • Pingback: Spring MVC @RequestBody @ResponseBody Example - WebSystique()

  • Pingback: Spring 4 MVC+AngularJS CRUD Example using $http service - WebSystique()

  • Pingback: Spring 4 MVC+Hibernate 4+MySQL+Maven integration + Testing example using annotations - WebSystique()

  • Pingback: Spring MVC 4 FileUpload-Download Hibernate+MySQL Example - WebSystique()

  • Pingback: Spring MVC 4 File Upload Example using Commons fileupload - WebSystique()

  • Pingback: Spring MVC 4 File Upload Example using Servlet 3 MultiPartConfigElement - WebSystique()

  • Pingback: Spring 4 Email With Attachment Tutorial - WebSystique()

  • Pingback: Spring 4+JMS+ActiveMQ Example with Annotations - WebSystique()

  • Pingback: Spring 4 + Quartz Scheduler Integration Example - WebSystique()

  • Pingback: Spring Job Scheduling using TaskScheduler (XML Config) - WebSystique()

  • Pingback: Spring 4 + Hibernate 4 + MySQL+ Maven Integration example (Annotations+XML) - WebSystique()

  • Pingback: Spring @Profile Guide - WebSystique()

  • Pingback: Spring Dependency Injection Annotation Example, Beans Auto-wiring using @Autowired, @Qualifier & @Resource Annotations Configuration - WebSystique()

  • Ah Med

    hello , I need an advice

    • websystique

      Hi, you can write me here or via contact page.

      • Ah Med

        Hello , I sent you via Contact page

  • Mouna Jaziri

    Ihave this problem please help
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory’ defined in class path resource [com/websystique/springboot/configuration/JpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean]: Factory method ‘entityManagerFactory’ threw exception; nested exception is java.lang.IllegalStateException: required key [datasource.sampleapp.hibernate.dialect] not found

    • websystique

      Hello Mouna, this problem has been discussed before. Main issue was that to run this application we needed to have a profile. A default profile has been enabled. you can as well override that profile using following:

      $> java -jar target/SpringBootCRUDApplicationExample-1.0.0.jar –spring.profiles.active=local

      • Irfan Nasim

        i dont have that jar file. project is not being run. i am trying to run from intelliJ and providing arguments in configuration files but failed.

  • http://www.sanjeev-kulkarni.blogspot.com Sanjeev Kulkarni

    Thanks for the wonderful article. This is very useful. However I am getting the below exception. Could you please let me know why I am getting this exception would be of great help.

    Error creating bean with name ‘restApiController’: Unsatisfied dependency expressed through field ‘userService’; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘userService’: Unsatisfied dependency expressed through field ‘userRepository’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘userRepository’: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class com.myapp.springboot.model.User

    Thanks again.
    Sanjeev

    • http://www.sanjeev-kulkarni.blogspot.com Sanjeev Kulkarni

      Hi,

      I got the problem as to why it was arising and got to know that I had missed proper package name in LocalContainerEntityManagerFactoryBean() method.

      Thanks. Keep writing. Kudos..
      Sanjeev

  • Raushan Kumar

    Hi ,I am getting error of

    “NetworkError: 401 Unauthorized – http://localhost:8080/SpringBootCRUDApp/api/user/
    Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/SpringBootCRUDApp/api/user/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

    • websystique

      Hi Raushan, for that you need to enable CORS on your server. Please have a look at this post. Basically take the CORSFilter class from above link and declare as a bean in your configuration.

      • Raushan Kumar

        Hi I have applied the custom filter and I am able to see that filter is getting hit and in log able to see the :::

        ………………….
        2017-03-03 10:10:57.637 INFO 2584 — [ main] o.s.j.e.a.AnnotationMBeanExporter : Located MBean ‘dataSource’: registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource]
        2017-03-03 10:10:57.925 INFO 2584 — [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8888 (http)
        2017-03-03 10:10:57.933 INFO 2584 — [ main] c.w.springboot.SpringBootCRUDApp : Started SpringBootCRUDApp in 10.31 seconds (JVM running for 11.894)
        2017-03-03 10:11:15.811 INFO 2584 — [nio-8888-exec-1] o.a.c.c.C.[.[.[/SpringBootCRUDApp] : Initializing Spring FrameworkServlet ‘dispatcherServlet’
        2017-03-03 10:11:15.811 INFO 2584 — [nio-8888-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet ‘dispatcherServlet’: initialization started
        2017-03-03 10:11:15.864 INFO 2584 — [nio-8888-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet ‘dispatcherServlet’: initialization completed in 53 ms
        Filtering on…………………………………………………..
        Filtering on…………………………………………………..
        Filtering on…………………………………………………..
        Filtering on…………………………………………………..
        Filtering on…………………………………………………..
        Filtering on…………………………………………………..
        Filtering on…………………………………………………..
        Filtering on…………………………………………………..
        Filtering on…………………………………………………..
        Filtering on…………………………………………………..
        Filtering on…………………………………………………..
        ………………………………………………………………………

        Another class I have created for SpringBootCRUDAppInit which extends AbstractAnnotationConfigDispatcherServletInitializer but this class is not getting hit and still having same issue.

        just wanted to now is there anything we need to add in js part.

        Thanks
        Raushan

        • websystique

          Hi, you don’t need anything else.Looking at your logs
          2017-03-03 10:10:57.925 INFO 2584 — [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8888 (http). Port is 8888.

          • Raushan Kumar

            Yes,I have changed port number

  • Phelan Lemieux

    Hey awesome tutorial. Any idea why I would be getting a Whitelabel Error Page when trying to access from the web browser?

    • websystique

      Hi Phelan, We overrode the Whitelabel error page using error.ftl in this example, so as per the official documentation, you shouldn’t be getting that error page. I wonder if you have some changes wrt download?

      • Phelan Lemieux

        Hi! I figured out the issue. I was using a newer version of spring boot and I guess the Maven references had not completely updated so I removed everything from the repository folder and re-updated and it worked. My fault!

  • Pingback: Spring MVC 4 RESTFul Web Services CRUD Example+RestTemplate - WebSystique()

  • Akash Agrawal

    Hey Websystique, I followed this tutorial to build my application, but after I run the project I get the following error:
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory’ defined in class path resource [bills/configuration/JpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean]: Factory method ‘entityManagerFactory’ threw exception; nested exception is java.lang.IllegalStateException: required key [datasource.sampleapp.hibernate.dialect] not found

    I get the same error when I try to run your code as is. I understand that this issue has been discussed before, but the solutions recommended there don’t work. I double checked the application.yml file for syntax errors, also tried changing the profiles, but same error always.
    Am I missing something here? Please help

    • Roberto Londei

      Me same!

      • websystique

        Roberto, the code shown here is a working app on Eclipse Mars with no known issue. As i asked above, please share a copy of your code which is not working for you [ a GITHUB e.g.]

        • Roberto Londei

          Issue is that on paragraph “Run the application –> Via Command line”
          the command seems to have just one minus sign for the schema, so if you type in:

          $> java -jar target/SpringBootCRUDApplicationExample-1.0.0.jar -spring.profiles.active=local

          you got a BeanCreationException and if you copy and paste the command as it is you also get an error because there is a strange sign before the minus sign.

          Obviously adding the default schema flag partially corrected the issue because it will newer start with no schema to load the bean from, but the correct solution here is to add two minus sign before the schema call while running the application, as follows:

          $> java -jar target/SpringBootCRUDApplicationExample-1.0.0.jar –spring.profiles.active=local

          or

          $> java -jar target/SpringBootCRUDApplicationExample-1.0.0.jar –spring.profiles.active=prod

          users that setup the application on eclipse didnt noticed that because eclipse automatically set the correct flag.

          Dear websystique, really thanks again for your work, i learned a lot from this post, it is always a pleasure to read updates from your site. ciao

          • websystique

            Hello Roberto, The command mentioned in the blog

            java -jar target/SpringBootCRUDApplicationExample-1.0.0.jar –spring.profiles.active=local

            indeed contains two ‘-’, compare the one before 1.0.0 with the one before ‘spring’. But i admit i should have been explicit in that. Thanks a ton for pointing it out.

          • Mouna Jaziri

            please can you explain more :/ i did’nt understand how i fix this prolem :( thank you

          • Mouna Jaziri

            please can you explain more :/ i did’nt understand how i fix this prolem. thank you

          • Roberto Londei

            come on man you just have to put two minus signs (“–”) behind the argument
            –spring.profiles.active=

          • Mouna Jaziri

            i’m not talking about the minus signs, i did’nt understand the methode

          • Irfan Nasim

            how to run in Intellij? i have tried to add program argument but still getting this error.

    • websystique

      Hello Akash, this error was indeed comming due to absence of a default profile, which i then added.So you should not get this issue anymore. Now, if you are still getting the same issue, it could be related to application.yml. The YML files are too picky when it comes to spaces or any extra character.May i ask you to share your code somehow [through GITHUB e.g.]

    • websystique

      Hello Akash, look at the reply from Roberto, probably this was the issue you were facing.

  • Luis Troya

    Hi. I am new to Spring, when I run my app I got this exception

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory’

    any ideas? I have the same dependencies as you but I got this exception

    • websystique

      Hello Luis, Could you please share your app which is not working for you, maybe a github link? The download in this post is a working app, and i can not reproduce this issue.

    • websystique

      Hello Luis, look at the reply from Roberto above, probably this was the issue you were facing.

  • Marko Uljarevic

    I have a big problem, when i start in NetBeans project, i have a message
    Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.2.1:exec, and i did everything and google but i can’t resolve my problem.
    When i put project in Eclipse, and start i got message HTTP Status 404, and can’t start.

    Can someone help me, or go on Teamweaver and resolve my problem?

    Thanks a lot :)

    • websystique

      Hello Marko, did you additionally once try to build the proect [mvn clean package] on command line and see if you still have this issue?This example has been tested on Eclipse without getting such issues.

      • Marko Uljarevic

        Yes, I see you write this code on Eclipse, but i still have problem, and i don’t know how to resolve him :( I try everything and i can’t start project :( Can you come on TW and try to see where is problem?

        Thanks :)

        • websystique

          Hello Marko, did you have your project somewhere on Github? I would give a try on my Eclipse MARS.1 version. Please note that the download in this example is a working App with no known issue.

  • Umar Hussain

    Hello Websystique : in JpaConfiuration class the dataSource() Method keeps giving error

    Required:
    org.apache.tomcat.jdbc.pool.DataSource
    Found:
    com.zaxxer.hikari.HikariDataSource

    • websystique

      Hi Umar, We are using Hikari pools here, so make sure that Hikari Dependency is included in pom.xml. By default, Spring boot gives first priority to Tomcat pooling if it is present, else next it looks for HikariCP. If you don’t want to use HikariCP, then you need to configure your own datasource bean with respective properties.

  • Umar Hussain

    Hello websystique : when ever i try to donwload the source code for
    http://websystique.com/spring-boot/spring-boot-angularjs-spring-data-jpa-crud-app-example/

    windows defender doesnt allows it and keeps sedning popup for trojan virus in the downloaded file

    • websystique

      Hi Umar, It’s a false flag from Windows-defender. I use paid version of anti-virus on all my systems, and this is not the first time someone reported about windows-defender issue. May be its time to turn it off and look for other anti-virus solutions.

  • kishore

    Hello websystique:

    Runtime application.yml file is not recognizing ,Because of that for I did hard code the DB parameters.

    Any quick hint.

    • websystique

      The one from post should work as it is. If your application.yml has been changed, make sure it is valid. Yml’s are very picky about the syntax; sometimes even a single space here or there can create a problem. You can use the online yml validator i mentioned in the post above. You can also use some text editor like Notepad++ , enabling the ‘show white spaces’ to see if you have any special characters in your yml file.

  • Neha

    Hello,

    I am getting the Caused by: java.lang.IllegalStateException: required key [datasource.sampleapp.hibernate.dialect] not found error. What is the issue ?

    • websystique

      Hello Neha, This property is defined in application.yml. Please make sure that your application.yml [or application.properties] file contains this value.

      • Neha

        Yes, value already contains there. I’ve not changed anything. It looks to me that file is not loading. What you say ?

        • websystique

          Did you use one of the mentioned profile?

          • Neha

            yes

        • websystique

          Hello Neha, I’ve updated the post [application.yml] to additionally use default profile as well. This way while running form within IDE we don’t have to specify the profile, default would be used. But you are still free to specify a different profile as shown in the post. Hope it clarifies.

          • Neha

            Thank you so mjuch.

  • manjush b

    Hi websystique, How this example can be achieved , by using Maven Multimodule, I tried , but i couldn’t make it working

    • websystique

      Hi Manjush,

      For multi-module, your parent-pom can extend from spring-boot-starter-parent. Rest of the module-level [which has the parent as your parent-pom] setup won’t change at all. In case you don’t want to extend, you can use ‘import’ instead. Reference doc explains it very well.


      org.springframework.boot
      spring-boot-dependencies
      1.4.3.RELEASE
      pom
      import

  • Alonso Quijano

    HI websystique
    In first THANKS (from a dinosaur avoiding her extinction)
    2°..is possible (recomendable) to run thats examples in the STS?…any link? (sorry by my English)

    • websystique

      Hi Alonso, the example itself has been created on Eclipse, but there is no reason it would not work on STS. Please make sure that your setup is fine. Let me know if you face any issue.

  • Roberto Londei

    Hello websystique,

    thanks a lot, this is really cool!!
    Can you please update this project with a token based authentication system and maybe separate the front-end Angularjs on a project using nodejs and npm http-server.

    Thanks!!!

  • Pingback: Hibernate Many-To-Many Bidirectional (Annotation) - WebSystique()

  • Pingback: Spring Batch & Quartz Scheduler Example (Tasklet usage) - WebSystique()

  • Pingback: Spring Batch- MultiResourceItemReader & HibernateItemWriter example - WebSystique()

  • Pingback: Spring Batch- Read an XML file and write to MySQL Database - WebSystique()

  • Pingback: Spring Batch- Read an XML file and write to a CSV file - WebSystique()

  • Pingback: Spring Batch- Read a CSV file and write to an XML file - WebSystique()

  • Pingback: Spring Security 4 Custom Login Form Annotation+XML Example - WebSystique()

  • Pingback: Spring Security 4 Logout Example - WebSystique()

  • Pingback: Spring Security 4 Secure View Fragments using taglibs - WebSystique()

  • Pingback: Spring Security 4 Hibernate Integration Annotation+XML Example - WebSystique()

  • Pingback: Spring Security 4 Hibernate Password Encoder Bcrypt Example - WebSystique()

  • Pingback: Secure Spring REST API using Basic Authentication - WebSystique()

  • Pingback: Secure Spring REST API using OAuth2 - WebSystique()

  • Pingback: Spring 4 Email Integration Tutorial - WebSystique()

  • Pingback: Spring 4+JMS+ActiveMQ example with @JmsListener & @EnableJms - WebSystique()

  • Pingback: Spring Job Scheduling with @Scheduled & @EnableScheduling Annotations - WebSystique()

  • Pingback: Spring @PropertySource & @Value annotations example - WebSystique()

  • Pingback: Spring Auto-detection autowire & Component-scanning Example With Annotations - WebSystique()

  • Pingback: Spring Dependency Injection Example with Constructor and Property Setter (XML) - WebSystique()

  • Pingback: Spring 4 Hello World Example - WebSystique()

  • Pingback: Spring 4 Email using Velocity,Freemarker Template library - WebSystique()

  • Pingback: Spring 4 MVC+Apache Tiles 3 Example - WebSystique()

  • Pingback: Spring 4 MVC ContentNegotiatingViewResolver example - WebSystique()

  • Pingback: Spring 4 MVC Form Validation and Resource Handling (Annotations) - WebSystique()

  • Pingback: Spring 4 MVC+AngularJS CRUD Application using ngResource - WebSystique()

  • Pingback: Spring MVC 4 File Download Example - WebSystique()

  • Pingback: Spring 4 MVC + JMS + ActiveMQ annotation based Example - WebSystique()

  • Pingback: Spring 4 MVC HelloWorld Tutorial - Annotation/JavaConfig Example - WebSystique()

  • Pingback: Spring 4 MVC HelloWorld Tutorial - Full XML Example - WebSystique()