I have a problem. I created Spring MVC + Thymeleft project but can't integrate properly, I read many guides and documentations, but nothing to help me. What's problem? Page load and no errors but no relevant information.. My code:
spring.xml
<?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:aop="http://www.springframework.org/schema/aop"
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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/practick" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<!-- Hibernate 3 Annotation SessionFactory Bean definition-->
<bean id="hibernate3AnnotatedSessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>SpringMVC1.model.Store</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<prop key="hibernate.enable_lazy_load_no_trans">false</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<mvc:resources mapping="/SpringMVC1/**" location="/WEB-INF/views" />
<!-- class beans -->
<bean id="storeDAO" class="SpringMVC1.dao.Impl.StoreDAOImpl">
<property name="sessionFactory" ref="hibernate3AnnotatedSessionFactory" />
</bean>
<bean id="storeModel" class="SpringMVC1.model.Store">
</bean>
<!-- Thymeleaf -->
<bean id="templateResolver"
class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/views/" />
<property name="suffix" value=".jsp" />
<property name="templateMode" value="HTML5" />
</bean>
<bean id="templateEngine"
class="org.thymeleaf.spring3.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
<property name="additionalDialects">
<set>
<bean class = "org.thymeleaf.spring3.dialect.SpringStandardDialect"/>
</set>
</property>
</bean>
<bean class="org.thymeleaf.spring3.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
<property name="order" value="1" />
<property name="viewNames" value="*.html,*.xhtml,*.jsp" />
<property name="excludedViewNames">
<array>
<value>home.jsp</value>
</array>
</property>
</bean>
</beans>
In pom.xml insert dependency:
<!-- Thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring3</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
Prototype of controller
#Controller
public class HomeController {
#Autowired
private ServletContext servletContext;
TemplateEngine templateEngine;
private static Store store;
private static StoreDAOImpl storeDAOImpl;
static List<Store> storess;
static{
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
storeDAOImpl = (StoreDAOImpl)context.getBean("storeDAO");
store = (Store)context.getBean("storeModel");
}
/*
#RequestMapping(value="/home")
public ModelAndView handleRequest(HttpServletRequest req,
HttpServletResponse resp) throws Exception {
ModelAndView modelAndView = new ModelAndView("home");
//modelAndView.addObject("storeList", storeDAO.getAllStores());
return modelAndView;
}
#RequestMapping(value = "/storeModel")
public ModelAndView root(#PathVariable String appBeanId, Locale locale,
org.springframework.ui.Model model) {
appBeanId="storeModel";
locale.getCountry();
store.setName("store1");
model.addAttribute("store1", store);
return new ModelAndView("home");
}
*/
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
#RequestMapping(value = "/home")
public String login(#Validated Store store, Model model) {
model.addAttribute("storeName", "sometext");
return "home";
}
/*
//public static List stores = storeDAOImpl.getAllStores();
#RequestMapping(value = "/listStores")
public ModelAndView y(HttpServletRequest req,
HttpServletResponse resp) throws SQLException, IOException {
store.setName("store1");
WebContext webContext = new WebContext(req, resp, servletContext);
webContext.setVariable("stores", storeDAOImpl.getAllStores());
webContext.setVariable("store1", store);
return new ModelAndView("home");
}
*/
}
And home.jsp:
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Home</title>
</head>
<body>
<h1>Hello World!</h1>
<p>This is the stores!</p>
<!-- <c:forEach items="${storeList}" var="store">
${store.name} ${store.type}: ${store.address}
<br />
</c:forEach>
-->
<table>
<caption> Store #2</caption>
<tr></tr>
<td><span th:text = "${storeName}">0</span></td>
</table>
</body>
</html>
as I know for returning jsp page from controller u should use smth like :
return new ModelAndView("home.jsp")
here was question about returning jsp
if String returned like u do it use for returning html page with stored in classpath. in context of thymeleaf it usually named template.
and why a u trying to use both thymeleaf and jsp. I could be wrong, but these are two competing technologies.
On official thymeleaf site : "Thymeleaf offers a set of Spring integrations that allow you to use it as a full-featured substitute for JSP in Spring MVC applications."
I posted a working (tested with jetty) solution in a public github project.
Related
Spring Transaction Hibernate #Transaction annotation is not working with #Autowired correctly. If I create the Dao`` element byxml(UserDao2 userDao2)`,
the transactional anotation in the Service class is working, if its by #Repository annotation in the Dao class when tries to getCurrentSesion, says:
org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97) ~[spring-orm-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:993) ~[hibernate-core-4.2.11.Final.jar:4.2.11.Final]
It appears that is not linking well the #Transactional annotation with the session factory
Library versions:
<jdk.version>1.6</jdk.version>
<spring.version>3.2.8.RELEASE</spring.version>
<spring.security.version>3.2.3.RELEASE</spring.security.version>
<hibernate.version>4.2.11.Final</hibernate.version>
spring-database.xml
<context:annotation-config />
<jee:jndi-lookup id="datasourcenn" jndi-name="java:/comp/env/nn_datasource" />
<bean id="sesionHibernate"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="datasourcenn"/>
<property name="packagesToScan" value="com.web.entity"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9iDialect</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.show_sql">true</prop>
<!-- nuevas properties de configuraciĆ³n -->
<prop key="hibernate.c3p0.min_size">5</prop>
<prop key="hibernate.c3p0.max_size">50</prop>
<prop key="hibernate.c3p0.timeout">300</prop>
<prop key="hibernate.c3p0.max_statements">50</prop>
<prop key="hibernate.bytecode.provider">cglib</prop>
</props>
</property>
</bean>
<bean id="us" class="com.web.dao.UserDaoImpl">
<property name="sesionHibernate" ref="sesionHibernate" />
</bean>
<!-- -->
<bean id="userDao2" class="com.web.dao.UserDao2Impl">
<property name="sesionHibernate" ref="sesionHibernate" />
</bean>
<bean id="myUserDetailsService" class="com.web.service.UsuarioServiceImpl">
<property name="userDao" ref="us" />
</bean>
<!--
proxy-target-class="true" mode="aspectj"
-->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sesionHibernate"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
UserDao2 (I remove #Repository if I create it by xml)
#Repository
public class UserDao2Impl implements UserDao2 {
private static Logger log = LoggerFactory.getLogger(UserDao2Impl.class);
#Autowired
#Qualifier("sesionHibernate")
private SessionFactory sesionHibernate;
#SuppressWarnings("unchecked")
public Usuario findByUserName(String username) {
try {
log.info("findByUserName" + sesionHibernate);
List<Usuario> users = new ArrayList<Usuario>();
System.out.println(sesionHibernate+"\n----------");
users = sesionHibernate.getCurrentSession().createQuery("from Usuario where nombre=?").setParameter(0, username).list();
// users = sesionHibernate.getCurrentSession().createQuery("from Usuario
// where nombre=?").setParameter(0, username).list();
if (users.size() > 0) {
return users.get(0);
} else {
return null;
}
} catch (Exception e) {
log.error("findByUserName ", e);
return null;
}
}
Usuario2ServiceImpl If have the service with #Transacional
#Service
#Transactional
public class Usuario2ServiceImpl implements Usuario2Service {
private static Logger log = LoggerFactory.getLogger(Usuario2ServiceImpl.class);
//Qualifier("userDaoImpl")
#Autowired
private UserDao2 userDao2;
#Override
public com.web.entity.Usuario getUsuariodetalles(final String nombreUsuario) throws UsernameNotFoundException {
log.info("getUsuariodetalles - 1");
System.out.println("ssss"+userDao2);
com.web.entity.Usuario usuario = userDao2.findByUserName(nombreUsuario);
log.info("getUsuariodetalles - 2");
return usuario;
}
Did you try putting #Transactional annotation at service layer method, you have placed it on class. I think it should work.
I solved in Tomcat the issue by putting in the spring-database.xml the next line:
<context:load-time-weaver aspectj-weaving="autodetect"/>
But it doesn't work in JBoss, which is where i need to deploy the final version. Other solution?
In Jboss i need to create both things in the xml(Service and Dao), keeping the transactional annotatations. But i doesn't work if create them(dao & service) with #Repository or #Service.
Solution, i add to mvc-dispatcher-servlet.xml, mvc:interceptors configuration to open session with org.springframework.orm.hibernate4.support.OpenSessionInViewInterceptor. Just need to define the sessionFactory in the properties.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
">
<context:annotation-config />
<context:component-scan base-package="com.web" />
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean name="OpenSessionInViewInterceptorCom" class="org.springframework.orm.hibernate4.support.OpenSessionInViewInterceptor">
<property name="sessionFactory">
<ref bean ="sesionHibernate" />
</property>
</bean>
</mvc:interceptor>
</mvc:interceptors>
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven />
<mvc:resources mapping="/css/**" location="/css/" />
<mvc:resources mapping="/img/**" location="/img/" />
<mvc:resources mapping="/js/**" location="/js/" />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
I am trying to do Spring 4 + Hibernate 4 configuration. But I am facing sessionFactory = null in the Controller. Below are the configurations and code.
What is the mistake in this configuration?
spring-database.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- MySQL data source -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/personal" />
<property name="username" value="root" />
<property name="password" value="password" />
</bean>
<!-- Hibernate session factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>/orm/Song.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
<bean id="songDao" class="com.letsdo.impl.SongImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- MUST have transaction manager, using aop and aspects -->
<tx:annotation-driven/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
</beans>
orm/Song/hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.letsdo.model.Song" table="song" catalog="personal">
<id name="id" type="int">
<column name="id" length="45" />
<generator class="increment"/>
</id>
<property name="filePath" column="filepath"/>
<property name="fileName" column="filename"/>
<property name="album" column="album"/>
<property name="title" column="title"/>
<property name="size" column="size"/>
</class>
</hibernate-mapping>
SongDao.java
public interface SongDao {
public List<String> getAllAlbums();
}
SongImpl.java
#Service
#Transactional
public class SongImpl implements SongDao{
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
public List<String> getAllAlbums(){
List<String> allAlbums = new ArrayList<String>();
Query query = getSessionFactory().getCurrentSession().createQuery("Select DISTINCT Album from song");
allAlbums = query.list();
return allAlbums;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
Controller: HomeController.java
public class HomeController {
#Autowired private SongImpl songDao;
#RequestMapping(value="/", method=RequestMethod.GET)
public ModelAndView welcomePageBeforeLogin(HttpServletRequest request, HttpServletResponse response,HttpSession session){
ModelAndView model = new ModelAndView();
List<String> album = songDao.getAllAlbums();
model.addObject("albumsize",album.size());
model.setViewName("hello");
return model;
}
}
I think you are ending up with two beans of class SongImpl - one that is defined in xml (named songDao), and another one annotated with #Service (named by default songImpl). The latter one has no SessionFactory autowired, that's why it is null.
You can find more info about it in one of the answers here.
If component scanning is enabled, spring will try to create a bean
even though a bean of that class has already been defined in the
spring config xml. However if the bean defined in the spring config
file and the auto-discovered bean have the same name, spring will not
create a new bean while it does component scanning.
The solution is to remove the xml version of the bean (if you don't need it), and to autowire SessionFactory in SongImpl.
on submitting form to addUser controller exception occured
SEVERE: Servlet.service() for servlet dispatcherServlet threw exception
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'userBean' on field 'email': rejected value [hello]; codes [Email.userBean.email,Email.email,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userBean.email,email]; arguments []; default message [email]]; default message [Not a vaild Email Address]
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:111)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:75)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:156)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:581)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:744)
Controller for getting Form
#RequestMapping(method = RequestMethod.GET, value = "register")
public String addUser(Model model) {
if (!model.containsAttribute("wrongLink")) {
System.out.println("not wrong Link");
model.addAttribute(new UserBean());
} else {
System.out.println("wrong Link");
}
return "user/register";
}
Controller to post form
#RequestMapping(method = RequestMethod.POST, value = "register")
public String addUser(#Valid UserBean userBean, Model model,
RedirectAttributes redirectAttrs, BindingResult bindingResult) {
System.out.println("in addUser form");
if (bindingResult.hasErrors()) {
System.out.println("ERROR in user Form");
return "user/edit";
}
return "redirect:/users/" + user.getDisplayName();
}
UserBean class
import org.hibernate.validator.constraints.Email;
public class UserBean {
private Integer id;
#Email(message = "Not a vaild Email Address")
private String email;
//getter and setter
}
Form
<div id="container">
<sf:form method="POST" modelAttribute="userBean">
<div class="form">
<sf:input path="email" type="text" id="email"
placeholder="email address" />
<sf:errors path="email" cssClass="error" />
<input class="send submit" type="submit" name="submit_first"
id="submit_first" value="" />
</div>
</sf:form>
</div>
spring.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
xmlns:tx="http://www.springframework.org/schema/tx">
<context:component-scan base-package="com.example" />
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${smtp.host}" />
<property name="port" value="${smtp.port}" />
<property name="username" value="${smtp.username}" />
<property name="password" value="${smtp.password}" />
<property name="javaMailProperties">
<props>
<!-- Use SMTP transport protocol -->
<prop key="mail.transport.protocol">smtp</prop>
<!-- Use SMTP-AUTH to authenticate to SMTP server -->
<prop key="mail.smtp.auth">true</prop>
<!-- Use TLS to encrypt communication with SMTP server -->
<prop key="mail.smtp.starttls.enable">true</prop>
<prop key="mail.debug">true</prop>
</props>
</property>
</bean>
<bean id="alertMailMessage" class="org.springframework.mail.SimpleMailMessage">
<property name="from" value="${alertMailMessage.from}" />
<property name="to" value="${alertMailMessage.to}" />
<property name="subject" value="${alertMailMessage.subject}" />
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="1000000" />
</bean>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<mvc:resources mapping="/**" location="/resources/" />
<mvc:annotation-driven />
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/WEB-INF/properties/database.properties</value>
<value>/WEB-INF/properties/smtp.properties</value>
</list>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.example.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
why this exception is coming on entering invalid email rather than validation has to be performed.
In your controller's addUser method, your BindingResult needs to be immediately after the bean:
public String addUser(#Valid UserBean userBean, BindingResult bindingResult,
Model model, RedirectAttributes redirectAttrs) {
...
}
I cannot understand what is going wrong with my simple Spring MVC project with JPA repositories. Could you please give a hint.
Domain:
package com.test.app;
#Entity
#Table(name = "foo_table")
public class FooDomain {
#Id
#Column(name = "id", unique = true, nullable = false)
private Integer id;
#Column(name = "text", nullable = false)
private String text;
// getters & setters here...
}
Repository
package com.test.app;
#RepositoryDefinition(domainClass=FooDomain.class, idClass=Long.class)
public interface FooRepository extends CrudRepository<FooDomain, Long> {}
Controller
#Controller
public class HomeController {
#Autowired
private FooRepository fooRepository;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
model.addAttribute("rowsNumber", fooRepository.count());
return "home";
}
}
root-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns & xsi here...>
<context:annotation-config />
<!-- Defining folders containing bean components (#Component, #Service) -->
<context:component-scan base-package="ru.lexikos.app" />
<import resource="hibernate.xml" />
<import resource="repositories.xml" />
<context:component-scan base-package="com.test.app" />
</beans>
hibernate.xml
<?xml xmlns & xsi here...>
<context:property-placeholder location="classpath:db-connection.properties" />
<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.pass}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
</bean>
</beans>
repositories.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns & xsi here...>
<jpa:repositories base-package="com.test.app"/>
</beans>
Exception
ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMapppingContext': Invocation of init method failed; nested exception is ja
va.lang.IllegalArgumentException: At least one JPA metamodel must be present!
Caused by: java.lang.IllegalArgumentException: At least one JPA metamodel must be present!
Xstian is right. I've lost entityManagerFactory declaration. Here is a sample that is working for me now:
hibernate.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<context:property-placeholder location="classpath:db-connection.properties" />
<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.user}" />
<property name="password" value="${jdbc.pass}" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="database" value="MYSQL"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<!-- spring based scanning for entity classes>-->
<property name="packagesToScan" value="com.test.app"/>
</bean>
<!-- Enables the Hibernate #Transactional programming model -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<jpa:repositories base-package="com.test.app"/>
</beans>
I faced this issue, when I was using Hibernate 4 (SessionFactory for persistence way, instead of EntityManagers) with Spring Boot. Adding this got rid of the error. Perhaps helps someone.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.6.0.Final</version>
<exclusions>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>ejb3-persistence</artifactId>
</exclusion>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
</exclusion>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
In Spring 3.0.5 and before, it was possible to create a base controller test class that fetched the HandlerMapping object from the Spring Application Context to directly access and call into a controller's method via the URL. I found this approach to be really awesome because in addition to testing the controller's methods, I was also testing the path variables and such in my unit/integration tests.
With Spring 3.2.4, this approach appears not to be possible any longer due to the restructuring of how Spring deals with Url mappings. I see that Spring provides a new MVC test framework, but to be honest, I think it's design is too verbose and looks nothing like the rest of the framework or my application code. It also doesn't play nicely with intellisense features in IntelliJ. To be honest, I'd rather not use it.
So, is there an alternative way to test controller URL's that does not use the new Spring MVC test framework, like I was doing before? I have an existing project with 371 controller tests, and I'd REALLY like to avoid migrating everything over to use the Spring MVC test framework.
Here is the handle() method I was using to test controllers using Spring 3.0.5:
protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response) throws Exception {
final HandlerMapping handlerMapping = applicationContext.getBean(HandlerMapping.class);
final HandlerExecutionChain handler = handlerMapping.getHandler(request);
assertNotNull("No handler found for request, check you request mapping", handler);
final Object controller = handler.getHandler();
final HandlerInterceptor[] interceptors = handlerMapping.getHandler(request).getInterceptors();
for (HandlerInterceptor interceptor : interceptors) {
final boolean carryOn = interceptor.preHandle(request, response, controller);
if (!carryOn) {
return null;
}
}
return handlerAdapter.handle(request, response, controller);
}
protected ModelAndView handle(String method, String path, String queryString) throws Exception {
request.setMethod(method);
request.setRequestURI(path);
if(queryString != null) {
String[] parameters = queryString.split("&");
for(String parameter : parameters) {
String[] pair = parameter.split("=");
if(pair.length == 2) {
request.setParameter(pair[0], pair[1]);
} else {
request.setParameter(pair[0], "");
}
}
}
return handle(request, response);
}
protected ModelAndView handle(String method, String path, String attribute, Object object) throws Exception {
MockHttpSession session = new MockHttpSession();
session.setAttribute(attribute, object);
request.setSession(session);
return handle(method, path, null);
}
protected ModelAndView handle(String method, String path) throws Exception {
return handle(method, path, null);
}
Here is some test code illustrating how I was using the handle() method:
#Test
public void show() throws Exception {
ModelAndView modelAndView = handle("GET", "/courseVersion/1/section/1");
Section section = (Section) modelAndView.getModel().get("section");
assertEquals(1, section.getId());
}
Here is my servlet application context:
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:applicationContext.properties"/>
</bean>
<bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
</bean>
<security:global-method-security pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler"/>
</security:global-method-security>
<context:component-scan base-package="keiko.web.controllers"/>
<mvc:annotation-driven validator="validator" />
<mvc:interceptors>
<bean class="keiko.web.interceptors.IpValidationInterceptor" />
<bean class="keiko.web.interceptors.UnreadMessagesInterceptor" />
<bean class="keiko.web.interceptors.ThemeInterceptor" />
<bean class="keiko.web.interceptors.ApplicationMenuInterceptor" />
</mvc:interceptors>
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
<property name="freemarkerSettings">
<props>
<prop key="auto_import">lib/common.ftl as common, lib/layouts.ftl as layouts</prop>
<prop key="whitespace_stripping">true</prop>
</props>
</property>
<property name="freemarkerVariables">
<map>
<entry key="template_update_delay" value="0"/>
<entry key="default_encoding" value="ISO-8859-1"/>
<entry key="number_format" value="0.##"/>
<entry key="xml_escape">
<bean class="freemarker.template.utility.XmlEscape"/>
</entry>
</map>
</property>
</bean>
<bean id="contentNegotiatingViewResolver"
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1"/>
<property name="ignoreAcceptHeader" value="true" />
<property name="defaultContentType" value="text/html" />
<property name="mediaTypes">
<map>
<entry key="html" value="text/html"/>
<entry key="json" value="application/json"/>
</map>
</property>
<property name="useNotAcceptableStatusCode" value="true" />
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="contentType" value="text/html" />
<property name="order" value="2"/>
<property name="cache" value="${freemarker.cache}"/>
<property name="prefix" value=""/>
<property name="suffix" value=".ftl"/>
<property name="exposeSpringMacroHelpers" value="true"/>
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="contentType" value="application/json" />
</bean>
</list>
</property>
</bean>
<bean id="viewNameTranslator" class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator"/>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="1000000"/>
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="keiko.domain.courseauthor.SectionIsDelayedException">error/sectionIsDelayed</prop>
<prop key="keiko.service.director.CompanyHomepageClosedException">error/registrationClosed</prop>
<prop key="keiko.service.director.IpDeniedException">error/ipDenied</prop>
</props>
</property>
</bean>
</beans>
Basically your test method has been flawed basically from the start. There was always a possibility that there where more then 1 HandlerMapping and 1 HandlerAdapter. What you are basically doing is mimic the DispatcherServlet.
What you should do is lookup all HandlerMappings and HandlerAdapters and check if one of them has a match for the URL (i.e. returning a HandlerExecutionChain) and select the appropriate HandlerAdapter (calling the supports method). What you are doing is basically what the DispatcherServlet is doing.