I wrote this code:
Controller:
#Controller
#RequestMapping("/groups")
public class GroupController {
#Autowired
private GroupService groupService;
#RequestMapping
public String list(Model model) {
model.addAttribute("groups", groupService.getAllGroups());
return "groups";
}
}
dbConnect
public class dbConnect {
public dbConnect(){}
private JdbcTemplate jdbcTemplate;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void DatabaseConnection(){
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("org.postgresql.Driver");
driverManagerDataSource.setUrl("jdbc:postgres://xxx");
driverManagerDataSource.setUsername("x");
driverManagerDataSource.setPassword("xss");
this.jdbcTemplate=new JdbcTemplate(driverManagerDataSource);
}
}
Group Repo Interface
public interface GroupRepository {
List<Group> getAllGroups();
}
Group Repo Impl
#Repository
public class InMemoryGroupRepository implements GroupRepository {
public InMemoryGroupRepository(){}
private dbConnect data;
//#Autowired
public InMemoryGroupRepository(dbConnect dbConnect) {
this.data = dbConnect;
}
public List<Group> getAllGroups() {
return data.getJdbcTemplate().query("SELECT id_grupy, nazwa, id_egzaminatora, haslo, egzaminatorzy_id_egzaminatora FROM grupy", new RowMapper<Group>() {
public Group mapRow(ResultSet rs, int rowNum)
throws SQLException {
Group group = new Group();
group.setId_grupy(rs.getInt(1));
group.setNazwa(rs.getString(2));
group.setId_egzaminatora(rs.getInt(3));
group.setHaslo(rs.getString(4));
group.setEgzaminatorzy_id_egzaminatora(rs.getInt(5));
return group;
}
});
}
}
Group Service Interface
public interface GroupService {
List<Group> getAllGroups();
}
Group Service Impl
#Service
public class GroupServiceImpl implements GroupService {
#Autowired
private GroupRepository groupRepository;
public List<Group> getAllGroups() {
return groupRepository.getAllGroups();
}
}
When I try enter "/groups" I get this error:
I think that the problem is that database connection cannot be established. We excluded almost every possible mistake. We tried to use ArrayList instead of using database and it worked well. How can i fix it?
You have an error in your DB configuration. dbConnect class isn't managed by Spring and because of that you get NPE because since it isn't injected into your repository. I suggest using configuration below:
#Configuration
class PersistenceConfig {
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgres://xxx");
dataSource.setUsername("x");
dataSource.setPassword("xss");
return dataSource;
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
And repository implementation:
#Repository
public class GroupPostgresRepository implements GroupRepository {
private final JdbcTemplate jdbcTemplate;
public GroupPostgresRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<Group> getAllGroups() {
final String sql = "SELECT id_grupy, nazwa, id_egzaminatora, haslo, egzaminatorzy_id_egzaminatora FROM grupy";
return jdbcTemplate.query(sql, (rs, rowNum) -> {
Group group = new Group();
group.setId_grupy(rs.getInt(1));
group.setNazwa(rs.getString(2));
group.setId_egzaminatora(rs.getInt(3));
group.setHaslo(rs.getString(4));
group.setEgzaminatorzy_id_egzaminatora(rs.getInt(5));
return group;
});
}
}
Related
Hi there I am trying to create a student webapp with spring boot but i can't seem to get it to run as an error appears every time that hibernate sessionfactory can't be found and i should include a bean type of equal type in my configuration.
I thought I properly configured the webapp properly but i cant seem to get it to find my hibernate session factory which i configured in my DAO, any help on where i'm going wrong would be appreciated.
Here Spring boot launcher class
#SpringBootApplication(exclude = HibernateJpaAutoConfiguration.class)
#ComponentScan({"model", "controller", "dao", "service"})
public class StudentsApplication {
public static void main(String[] args) {
SpringApplication.run(StudentsApplication.class, args);
}
}
Here is my DAO class
#Repository
#Transactional
public class StudentDao {
#Autowired
SessionFactory sessionFactory;
public Student getStudent(final int id) {
#SuppressWarnings("unchecked")
TypedQuery<Student> q = sessionFactory.getCurrentSession().createQuery(
"from student where = id").setParameter("id", id);
return q.getSingleResult();
}
public List<Student> getAllStudents() {
#SuppressWarnings("unchecked")
TypedQuery<Student> q = sessionFactory.getCurrentSession().createQuery(
"from student");
return q.getResultList();
}
public void addStudent(final Student student) {
sessionFactory.getCurrentSession().save(student);
}
public void updateStudent(final Student student) {
sessionFactory.getCurrentSession().saveOrUpdate(student);
}
public void deleteStudent(final int id) {
sessionFactory.getCurrentSession().createQuery(
"delete from student where = id").setParameter("id", id)
.executeUpdate();
}
}
here is my configuration class
#Configuration
#PropertySource({"classpath:application.properties"})
public class DbConfig {
#Autowired
private Environment environment;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getProperty("jdbc.url"));
dataSource.setUsername(environment.getProperty("jdbc.username"));
dataSource.setPassword(environment.getProperty("jdbc.password"));
return dataSource;
}
#Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(dataSource());
Properties props = new Properties();
props.put("format_sql", "true");
props.put("hibernate.show_sql", "true");
factoryBean.setHibernateProperties(props);
factoryBean.setPackagesToScan("com.alpheus.students.entity");
// factoryBean.setAnnotatedClasses(Student.class);
return factoryBean;
}
#Bean
public HibernateTransactionManager getTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(getSessionFactory().getObject());
return transactionManager;
}
}
here is my properties file
# Connection url for the database
spring.datasource.url=jdbc:mysql://localhost:3308/week04
spring.datasource.username=user
spring.datasource.password=pass
server.port=9999
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
#view resolver
spring.mvc.view.prefix=/views/
spring.mvc.view.suffix=.jsp
here is my controller class
#Controller
public class StudentController {
#Autowired
private StudentService studentService;
#GetMapping("/home")
public String getAllStudents(Model studentsModel) {
List<Student> listStudents = studentService.getAllStudents();
studentsModel.addAttribute("listStudents", listStudents);
return "student-list";
}
#GetMapping("/student/{id}")
public String editStudent(#PathVariable int id, Model studentModel) {
studentModel.addAttribute("student", studentService.getStudent(id));
return "student-form";
}
#PostMapping("/student/new")
public String saveStudent(#ModelAttribute("student")Student student) {
studentService.addStudent(student);
return "redirect:/";
}
#GetMapping("/student")
public String showNewForm() {
return "student-form";
}
#PostMapping("/student/update/{id}")
public String updateStudent(#ModelAttribute("student") Student student) {
studentService.updateStudent(student);
return "redirect:/";
}
#GetMapping(value = "/student/delete/{id}")
public String deleteStudent(#PathVariable int id) {
studentService.deleteStudent(id);
return "redirect:/";
}
}
the problem is once i use method findAll using MongoOperation interface, it working fine with no exception but only return One Record, however the collection contain more than 1 record. i tried a different interface like mongotemp and also the same result, List size is return always 1, even when i try it from dao itself
Configuration Spring DATA with mongodb
#Configuration
public class MongodbConfig {
public #Bean MongoDbFactory mongoDbFactory() throws Exception {
return new SimpleMongoDbFactory(new MongoClient(), "inSpace");
}
public #Bean MongoTemplate mongoTemplate() throws Exception {
MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory());
return mongoTemplate;
}
}
DAO Class
#Repository
public class GenericDAOImpl<T> implements GenericDAO<T> {
#Autowired
protected MongoOperations mongoOper;
public <T> void save(T ct) {
mongoOper.save(ct);
}
public <T> void remove(T ct) {
mongoOper.remove(ct);
}
public T getBydId(String id, Class<T> clazz) {
return mongoOper.findById(id, clazz);
}
public List<T> getAll(Class<T> clazz) {
System.err.println(" ''''''' " + mongoOper.findAll(clazz).size());
return mongoOper.findAll(clazz);
}
}
Note: the upper two classs in a single project and used as dependency for the other project who contain the below classes
Service calling DAO
#Service("userService")
public class UserServiceImpl implements UserService {
#Autowired
private GenericDAO<Users> userDAO;
public Users create(Users user) {
userDAO.save(user);
return user;
}
public Users delete(String id) {
Users user = userDAO.getBydId(id, Users.class);
userDAO.remove(user);
return user;
}
public List<Users> findAll() {
System.out.println("inside User Service");
return userDAO.getAll(Users.class);
}
public Users findById(String id) {
return userDAO.getBydId(id , Users.class);
}
}
Controller Class
#RestController
#RequestMapping("/user")
public class UsersController {
#Autowired
UserService userService;
#RequestMapping(method = RequestMethod.GET, value = "/allUsers")
List<Users> getAllRegistedUsers() {
System.out.println("inside UserController");
return userService.findAll();
}
}
Configuration Class
#SpringBootApplication
#ComponentScan(basePackageClasses=
{UsersController.class,UserService.class,GenericDAO.class})
public class UsersConfiguration {
public static void main(String[] args) {
SpringApplication.run(UsersConfiguration.class, args);
}
}
Note: when i try to inject bean in Main methods and use the bean by ApplicationContext it's work fine and return all records in database !?
I wanted to do commit and rollback using jdbcTemplate.
My question is based on this thread
How do I commit or rollback, should I do it on jdbcTemplate like
jdbcTemplate.commit();
jdbcTemplate.rollback();
Or there are some other ways to achieve commit and rollback functionality using jdbcTemplate.
To call commit or rollback at will set the transactional boundaries programmatically and not declaratively.
For that reason you have to get hold of the PlatformTransactionManager - inject it that is in your DAO and perform the commit/ rollback operation yourself.
Sample code:
#Autowired private JdbcTemplate jdbcTemplate;
#Autowired private PlatformTransactionManager platformTransactionManager;
//..
public void daoMethod(params) {
DefaultTransactionDefinition paramTransactionDefinition = new DefaultTransactionDefinition();
TransactionStatus status=platformTransactionManager.getTransaction(paramTransactionDefinition );
try{
String sqlQuery = "query";
jdbcTemplate.update(sqlQuery, params);
platformTransactionManager.commit(status);
}catch (Exception e) {
platformTransactionManager.rollback(status);
}
Another approach is to get hold of the TransactionTemplate
Sample code:
#Autowired private JdbcTemplate jdbcTemplate;
#Autowired private TransactionTemplate transactionTemplate;
//..
//for operations where query does not return like delete
public void daoMethod(params) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus paramTransactionStatus) {
try{
String sqlQuery = "query";
jdbcTemplate.update(query, params);
}catch (Exception e) {
paramTransactionStatus.setRollbackOnly();
}
}
});
}
//for operations where query does return like insert
public int daoMethod(params) {
return transactionTemplate.execute(new TransactionCallback<Integer>() {
public Integer doInTransaction(TransactionStatus paramTransactionStatus) {
String sqlQuery = "query";
Object[] params = params;
int[] types = myTypes;
return jdbcTemplate.update(sqlQuery,params,types);
}
});
}}
Use #Transactional. But of course, before of that, you will have to create bean definition for DataSourceTransactionManager:
// Your DataSource bean definition
#Bean
public DataSource dataSource() {
....
}
// Transaction manager bean definition
#Bean
public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
And then you can use #Transactional. Example of service:
#Service
public class MyServiceImpl {
#Autowired
private MyDAO myDAO;
#Transactional
public void insert(Entity entity) {
myDAO.insert(entity);
}
}
the easiest way of managing transactions in spring is #Transactional annotation, so your code will look very simple:
#Transactional(rollbackFor = Exception.class)
public void doSomething(...) {
...
}
read more: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html
if you have configured the spring transaction manager / jdbcTemplate correctly , then you could always use the #Transactional annotations provided by spring in order to define when you want a transaction to be rolled back or not. But even if you have defined a rollback and your jdbc driver or your database do not allow transactions (check TRANSACTION_ISOLATION over JdbcConnection), then spring will log that is using transactions but the database will simply ignore those points.
#Configuration
public class ConfigurationApp {
#Bean
public DataSource dataSourceJdbc() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
dataSource.setUrl("jdbc:oracle:thin:#localhost:1521:orcl");
dataSource.setUsername("hossein");
dataSource.setPassword("myjava123");
dataSource.setDefaultAutoCommit(false);
return dataSource;
}
#Bean
public JdbcTemplate jdbcTemplate() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceJdbc());
return jdbcTemplate;
}
#Bean
public DAOImpl dao() {
DAOImpl personDAO = new DAOImpl();
personDAO.setJdbcTemplate(jdbcTemplate());
return personDAO;
}
#Bean
public PersonService personService() {
PersonService personService = new PersonService();
personService.setPersonDAO(dao());
return personService;
}
}
//////////////////////////////////////////
public class Person {
private Integer id;
private String name;
private String family;
private Integer password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFamily() {
return family;
}
public void setFamily(String family) {
this.family = family;
}
public Integer getPassword() {
return password;
}
public void setPassword(Integer password) {
this.password = password;
}
}
/////////////////////////////////////////
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public class DAOImpl {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public int add(Person person) {
String sql = "insert into person(id,name,family,password) values(?,?,?,?)";
return this.jdbcTemplate.update(sql, person.getId(), person.getName(), person.getFamily(), person.getPassword());
}
public void commit(){
BasicDataSource basicDataSource= (BasicDataSource) jdbcTemplate.getDataSource();
basicDataSource.setDefaultAutoCommit(true);
}
}
///////////////////////////////////
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class PersonService {
private DAOImpl personDAO;
public void setPersonDAO(DAOImpl personDAO){
this.personDAO=personDAO;
}
public void addPerson(Person person) {
personDAO.add(person);
this.personDAO.commit();
}
}
///////////////////////
public class MainApp {
public static void main(String[] args) {
Locale.setDefault(Locale.ENGLISH);
AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext(ConfigurationApp.class);
PersonService person=ac.getBean(PersonService.class);
Person person1=new Person();
person1.setId(896);
person1.setName("vali");
person1.setFamily("hassanpoor");
person1.setPassword(12579);
person.addPerson(person1);
}
I have problems with autowiring in Spring.
I have dao class for AccessLevel object like this:
Interface:
public interface AccessLevelDAO {
public AccessLevel select(Integer id);
}
It's implementation:
#Repository
public class AccessLevelDAOImpl implements AccessLevelDAO {
private SessionFactory sessionFactory;
#Autowired
public void AccessLevelDAO(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
private Session currentSession() {
return sessionFactory.getCurrentSession();
}
#Override
#Transactional(propagation = Propagation.SUPPORTS,
isolation = Isolation.READ_UNCOMMITTED)
public AccessLevel select(Integer id) {
return (AccessLevel) currentSession().createCriteria(AccessLevel.class).add(Restrictions.idEq(id)).uniqueResult();
}
}
And service class which using this DAO class:
Interface:
public interface UserServices {
String getUserAccessLevel(String username);
AuthorizationResponseDTO authorize(String username, String password);
}
And implementation:
#Service
public class UserServicesImpl implements UserServices {
#Autowired private AccessLevelDAO accessLevelDAO;
#Autowired private UserDAO userDAO;
#Override
public String getUserAccessLevel(String username) {
User user = userDAO.select(username);
return accessLevelDAO.select(user.getAccessLevel()).getAccessLevel();
}
#Override
public AuthorizationResponseDTO authorize(String username, String password) {
return null;
}
}
When I'm trying to #Autowire accessLevelDAO and userDAO i get error message "Could not autowire. No beans of "AccessLevelDAO" type found".
Spring config includes component scan definition:
<context:annotation-config />
<context:component-scan base-package="com.core"/>
I've been beating my head against a wall for awhile now trying to get this to work. I have created the following data access object:
public interface GenericDAO<T, ID extends Serializable> {
T findById(ID id);
List<T> findAll();
T save(T entity);
void update(T entity);
void delete(T entity);
}
public class GenericHibernateDAO<T, ID extends Serializable> implements GenericDAO<T, ID> {
private final Class<T> persistentClass;
private final SessionFactory sessionFactory;
public GenericHibernateDAO(final SessionFactory sessionFactory) {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
this.sessionFactory = sessionFactory;
}
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
public Class<T> getPersistentClass() {
return persistentClass;
}
#Override
public T findById(final ID id) {
return (T) getSession().load(getPersistentClass(), id);
}
#Override #SuppressWarnings("unchecked")
public List<T> findAll() {
return findByCriteria();
}
protected List<T> findByCriteria(final Criterion... criterion) {
final Criteria crit = getSession().createCriteria(getPersistentClass());
for (final Criterion c : criterion) {
crit.add(c);
}
return crit.list();
}
#Override
public T save(final T entity) {
getSession().saveOrUpdate(entity);
return entity;
}
#Override
public void delete(final T entity) {
getSession().delete(entity);
}
#Override
public void update(final T entity) {
getSession().saveOrUpdate(entity);
}
}
#Repository
public class StockHibernateDAO extends GenericHibernateDAO<Stock, String> implements StockDAO {
#Inject
public StockHibernateDAO(final SessionFactory sessionFactory) {
super(sessionFactory);
}
}
I'm attempting to set this up with Java Configuration, so here is my configuration to setup my service layer:
#Configuration #Profile("hibernate")
#EnableCaching #EnableTransactionManagement
#ComponentScan("reference.dao.hibernate")
public class HibernateServiceConfig implements TransactionManagementConfigurer {
#Inject private StockDAO stockDao; //No extra methods, just the base stuff for now
#Bean(destroyMethod = "shutdown")
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).addScript("classpath:schema.sql").build();
}
#Bean
public SessionFactory sessionFactory() {
return new LocalSessionFactoryBuilder(dataSource()).addAnnotatedClasses(Stock.class)
.setProperty("hibernate.show_sql", "true")
.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory")
.setProperty("hibernate.cache.use_query_cache", "true")
.setProperty("hibernate.cache.use_second_level_cache", "true")
.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect").buildSessionFactory();
}
#Override #Bean
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new HibernateTransactionManager(sessionFactory());
}
}
Here is the TradingService:
#Service
public class TradingServiceImpl implements TradingService {
#Inject private StockDAO stockDAO;
#Override #Transactional
#CachePut(value = "stockCache", key = "#stock.name")
public Stock addNewStock(final Stock stock) {
stockDAO.save(stock);
return stock;
}
#Override #Cacheable(value = "stockCache")
public Stock getStock(final String stockName) {
return stockDAO.findById(stockName);
}
#Override #CacheEvict(value = "stockCache", key = "#stock.name")
public void removeStock(final Stock stock) {
stockDAO.delete(stock);
}
#Override #CacheEvict(value = "stockCache", key = "#stock.name")
public void updateStock(final Stock stock) {
stockDAO.update(stock);
}
#Override
public List<Stock> getAll() {
return stockDAO.findAll();
}
}
The saving of a stock only seems to be completed if I add a session.flush() to the save method. The way I understand things, having the TransactionManager and the #Transactional around the service layer method should in fact cause that call to be made for me. What is this configuration missing?
Because you are injecting a Session
#Bean
public Session session() {
return sessionFactory().openSession();
}
Spring cannot add it's transactional behavior around it. Let Spring open the session and do it's business.
Instead of injecting a Session, inject a SessionFactory. In your DAO, keep a attribute for SessionFactory and use sessionFactory.getCurrentSession() to acquire a session.
When Spring sees the #Transactional, it will get the SessionFactory, call openSession(), begin a transaction on it, then call your method. When your method returns successfully, it will close that transaction.
You should also probably #Autowired the dao in your service class.