J'ai fini de lire le doc du printemps et l'exemple de projet PetClinic. Tout comme pour voir un plus grand projet du monde réel réalisé avec Spring. Merci.
Je travaille pour une grande compagnie d'assurance maladie où nous utilisons beaucoup Spring en backend. Je vais vous montrer comment est construite une application modulaire .
Squelette WEB-INF sans répertoire de classes
ar
WEB-INF
web.xml
/**
* Spring related settings file
*/
ar-servlet.xml
web
moduleA
account
form.jsp
moduleB
order
form.jsp
Squelette classes répertoire
classes
/**
* Spring related settings file
*/
ar-persistence.xml
ar-security.xml
ar-service.xml
messages.properties
br
com
ar
web
moduleA
AccountController.class
moduleB
OrderController.class
br
com
ar
moduleA
model
domain
Account.class
repository
moduleA.hbm.xml
service
br
com
ar
moduleB
model
domain
Order.class
repository
moduleB.hbm.xml
service
...
Remarquez comment chaque package sous br.com.ar.web correspond WEB-INF/view répertoire. C'est la clé nécessaire pour exécuter la convention sur la configuration dans Spring MVC. Comment ??? compter sur ControllerClassNameHandlerMapping
WEB-INF/ar-servlet.xml Remarquez la propriété basePackage, ce qui signifie rechercher n'importe quelle classe @ Controller sous br.com.ar.view package. Cette propriété vous permet de construire un contrôleur @ modulaire modulaire
<!--Scans the classpath for annotated components at br.com.ar.web package-->
<context:component-scan base-package="br.com.ar.web"/>
<!--registers the HandlerMapping and HandlerAdapter required to dispatch requests to your @Controllers-->
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
<property name="basePackage" value="br.com.ar.web"/>
<property name="caseSensitive" value="true"/>
<property name="defaultHandler">
<bean class="org.springframework.web.servlet.mvc.UrlFilenameViewController"/>
</property>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
Voyons maintenant, par exemple, AccountController
package br.com.ar.web;
@Controller
public class AccountController {
@Qualifier("categoryRepository")
private @Autowired Repository<Category, Category, Integer> categoryRepository;
@Qualifier("accountRepository")
private @Autowired Repository<Account, Accout, Integer> accountRepository;
/**
* mapped To /account/form
*/
@RequestMapping(method=RequesMethod.GET)
public void form(Model model) {
model.add(categoryRepository().getCategoryList());
}
/**
* mapped To account/form
*/
@RequestMapping(method=RequesMethod.POST)
public void form(Account account, Errors errors) {
accountRepository.add(account);
}
}
Comment ça marche ???
Supposons que vous fassiez une demande pour http://127.0.0.1:8080/ar/ moduleA/compte/formulaire .html
Spring supprimera le chemin entre le chemin de contexte et l'extension de fichier - mis en évidence ci-dessus. Lisons le chemin extrait de droite à gauche
qui est traduit en
br.com.ar.web.moduleA.AccountController.form
D'accord. Mais comment Spring sait-il quelle vue afficher ??? Voir ici
Et sur la persistance les problèmes liés ???
Tout d'abord, voyez ici comment nous implémentons le référentiel. Notez que chaque requête de module associée est stockée dans son package de référentiel associé . Voir squelette ci-dessus. Voici la propriété ar-persistence.xml Notice mappingLocations et packagesToScan
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/dataSource" resource-ref="true">
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingLocations">
<util:list>
<value>classpath:br/com/ar/model/repository/hql.moduleA.hbm.xml</value>
<value>classpath:br/com/ar/model/repository/hql.moduleB.hbm.xml</value>
</util:list>
</property>
<property name="packagesToScan">
<util:list>
<value>br.com.ar.moduleA.model.domain</value>
<value>br.com.ar.moduleB.model.domain</value>
</util:list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.connection.charSet">UTF-8</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.validator.autoregister_listeners">false</prop>
</props>
</property>
</bean>
</beans>
Notez que j'utilise Hibernate. JPA doit être correctement configuré.
Gestion des transactions et analyse des composants ar-service.xml Remarque Deux points après br.com.ar dans aop: attribut d'expression de pointcut qui signifie
Tout package et sous-package sous package br.com.ar
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="br.com.ar.model">
<!--Transaction manager - It takes care of calling begin and commit in the underlying resource - here a Hibernate Transaction -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:advice id="repositoryTransactionManagementAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="remove" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<tx:advice id="serviceTransactionManagementAdvice" transaction-manager="transactionManager">
<!--Any method - * - in service layer should have an active Transaction - REQUIRED - -->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="servicePointcut" expression="execution(* br.com.ar..service.*Service.*(..))"/>
<aop:pointcut id="repositoryPointcut" expression="execution(* br.com.ar..repository.*Repository.*(..))"/>
<aop:advisor advice-ref="serviceTransactionManagementAdvice" pointcut-ref="servicePointcut"/>
<aop:advisor advice-ref="repositoryTransactionManagementAdvice" pointcut-ref="repositoryPointcut"/>
</aop:config>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
</beans>
Test
Pour tester la méthode @Controller annotée, voir ici comment
Autre que la couche Web. Remarquez comment je configure une source de données JNDI dans la méthode @Before
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:ar-service.xml", "classpath:ar-persistence.xml"})
public class AccountRepositoryIntegrationTest {
@Autowired
@Qualifier("accountRepository")
private Repository<Account, Account, Integer> repository;
private Integer id;
@Before
public void setUp() {
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
DataSource ds = new SimpleDriverDataSource(new Oracle.jdbc.driver.OracleDriver(), "jdbc:Oracle:thin:@127.0.0.1:1521:ar", "#$%#", "#$%#");
builder.bind("/jdbc/dataSource", ds);
builder.activate();
/**
* Save an Account and set up id field
*/
}
@Test
public void assertSavedAccount() {
Account account = repository.findById(id);
assertNotNull(account);
}
}
Si vous avez besoin d'une suite de tests, procédez comme suit
@RunWith(Suite.class)
@Suite.SuiteClasses(value={AccountRepositoryIntegrationTest.class})
public void ModuleASuiteTest {}
web.xml est présenté comme suit
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://Java.Sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://Java.Sun.com/xml/ns/j2ee http://Java.Sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:ar-persistence.xml
classpath:ar-service.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>ar</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ar</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<resource-ref>
<description>datasource</description>
<res-ref-name>jdbc/dataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
J'espère que cela peut être utile. Mettre à jour le schéma vers Spring 3.0. Voir la documentation de référence Spring. schéma mvc, Pour autant que je sache, est pris en charge uniquement dans Spring 3.0. Garde ça en tête
Quelques candidats:
AppFuse - Dans AppFuse, le framework Spring est utilisé partout pour sa prise en charge Hibernate/iBATIS, les transactions déclaratives, la liaison de dépendance et le découplage de couche.
Equinox (a.k.a. AppFuse Light) - une application CRUD simple créée dans le cadre de Spring Live.
Spring by Example - Divers exemples Spring plus quelques bibliothèques téléchargeables.
Tudu Lists - Tudu Lists est une application J2EE pour gérer les listes de tâches. Il est basé sur JDK 5.0, Spring, Hibernate et une interface AJAX (en utilisant le framework DWR).
Regardez Apache CXF . Il utilise le printemps.