trumanblack1025
trumanblack1025

Reputation: 491

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userController'

The related questions doesn't seem to help me. It's my first time developing a webapp using spring boot and I've encountered this error. This is my code.

UserController

package com.rtc_insurance.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.rtc_insurance.dao.UserDAO;
import com.rtc_insurance.entity.Users;

@Controller
@RequestMapping("/user")
public class UserController {

    //inject DAO
    //scan for a component that implements UserDAO interface
    @Autowired
    private UserDAO userDAO;


    @RequestMapping("/list")
    public String listUsers(Model theModel) {

        //get user from the dao
        List<Users> theUsers = userDAO.getUsers();

        //add the customer to the model
        //users = table name
        theModel.addAttribute("users",theUsers);

        return "list-users";
    }
}

UserDAO

package com.rtc_insurance.dao;

import java.util.List;
import com.rtc_insurance.entity.Users;

public interface UserDAO {

    public List<Users> getUsers();
}

UserDAOImpl

package com.rtc_insurance.dao;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;


import com.rtc_insurance.entity.Users;

@Repository
public class UserDAOImpl implements UserDAO {

    //need to inject the session factory
    @Autowired
    private SessionFactory sessionFactory;

    @Override
    @Transactional
    public List<Users> getUsers() {

        //get current hibernate session
        Session currentSession = sessionFactory.getCurrentSession();

        //query
        Query<Users> theQuery = 
                currentSession.createQuery("from users", Users.class);

        //execute result
        List<Users> users = theQuery.getResultList();

        //return list of users
        return users;

    }

}

Servlet

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- Add support for component scanning -->
    <context:component-scan base-package="com.rtc_insurance" />

    <!-- Add support for conversion, formatting and validation support -->
    <mvc:annotation-driven/>

    <!-- Define Spring MVC view resolver -->
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <!-- Step 1: Define Database DataSource / connection pool -->
    <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/rtc_insurance?useSSL=false&amp;characterEncoding=latin1&amp;serverTimezone=UTC" />
        <property name="user" value="root" />
        <property name="password" value="root" /> 

        <!-- these are connection pool properties for C3P0 -->
        <property name="initialPoolSize" value="5"/>
        <property name="minPoolSize" value="5" />
        <property name="maxPoolSize" value="20" />
        <property name="maxIdleTime" value="30000" />
    </bean>  

    <!-- Step 2: Setup Hibernate session factory -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="dataSource" ref="myDataSource" />
        <property name="packagesToScan" value="com.rtc_insurance.entity" />
        <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
        </property>
</bean>   

    <!-- Step 3: Setup Hibernate transaction manager -->
    <bean id="myTransactionManager"
            class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <!-- Step 4: Enable configuration of transactional behavior based on annotations -->
    <tx:annotation-driven transaction-manager="myTransactionManager" />

    <!-- Add support for reading web resources: css, images, js, etc ... -->
    <mvc:resources location="/resources/" mapping="/resources/**"></mvc:resources>



</beans>

And I've been getting this error.

Upvotes: 1

Views: 485

Answers (1)

Dimitri Mestdagh
Dimitri Mestdagh

Reputation: 44745

Spring boot does a lot of things out of the box for you.

Configuring the DataSource

First of all, there is the datasource. Sadly, C3P0 isn't a supported connection pool providers (only DBCP, Hikari and Tomcat are). That means that you manually have to create a DataSource bean, for example:

@Bean
@ConfigurationProperties("custom.datasource")
public ComboPooledDataSource dataSource() {
    return new ComboPooledDataSource();
}

If you add this method to your main class, or any other class annotated with @Configuration, Spring will automatically pick up the datasource bean, and create a TransactionManager and a SessionFactory for you. It also enables annotation-driven transactions.

Since we're using @ConfigurationProperties, all properties that start with custom.datasource.* are automatically injected into the datasource. This allows you to configure your datasource from within application.properties. If you don't have such file yet, create one on the classpath and add the following properties:

custom.datasource.jdbc-url=jdbc:mysql://localhost:3306/rtc_insurance?useSSL=false&amp;characterEncoding=latin1&amp;serverTimezone=UTC
custom.datasource.user=root
custom.datasource.password=root
custom.datasource.initial-pool-size=5
custom.datasource.min-pool-size=5
custom.datasource.max-pool-size=20
custom.datasource.max-idle-time=30000

Replace DAO by Spring Data

The next part is the DAO. The Spring Data project tries to make these things a lot easier. First of all, you need to add the spring-boot-starter-data-jpa dependency to your project. If you're using Maven, you could do the following:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </exclusion>
    </exclusions>
</dependency>

The exclusion is optional, but allows you to exclude the default connection pool (which is Hikari) since you're not using it. After that, you can replace your entire UserDAO and UserDAOImpl by the following:

public interface UserRepository extends JpaRepository<User, Long> {
}

By creating an interface and extending from JpaRepository (or CrudRepository, ...), Spring knows that it should create a repository bean for you, with the type User and the identifier being of type Long (you didn't share your User entity, so if it's not a Long, you can change the generics).

It will also include some default methods, such as findAll(), findById(), save(), delete(), ... which you no longer have to write. Since you're getUsers() method is basically the same as the findAll() operation. That means you don't need that code, and you can just autowire the UserRepository into your controller, and use the findAll() operation.

Component scan

Within your XML configuration you also have a component scan:

<context:component-scan base-package="com.rtc_insurance" />

This is no longer necessary, since Spring boot will automatically scan for components within the same package, or any subpackage of the main class. If you want to add an additional componentscan, you can do so by adding the @ComponentScan("com.xyz") annotation on top of the main class, or any other class annotated with @Configuration.

Spring MVC configuration

You also have some configuration related to Spring MVC, such as:

  1. MVC annotation driven
  2. The pre- and suffix of the view resolver
  3. The location of the static resources

Since Spring boot automatically enabled MVC annotations, you can already scratch that. The pre- and suffix of the view resolver on the other hand can be configured through application.properties as well, by configuring the following properties:

spring.mvc.view.prefix=/WEB-INF/view/
spring.mvc.view.suffix=.jsp

And finally, there are the static resources. By default, Spring boot will automatically include resources from several locations such as classpath:/static/ and classpath:/public/ as static resource locations.

That means that if you put any file within those folders, it will be automatically served.

After that, your entire bean XML configuration file has become obsolete, and can be deleted.

Upvotes: 1

Related Questions