Статьи

REST CXF для бэкэнда Spring JPA2

В этой демонстрации мы создадим приложение REST / CXF с бэкэндом spring / jpa2.

Это демо представляет трек REST-CXF минуты проекта.

Модель из демо 2 осталась прежней.

Обогащение остается прежним.

Но треки меняются

Что добавлено 2 слоя:

  • слой DAO с пружинной интеграцией поверх JPA2
  • слой REST-CXF с аннотацией JAX-RS

Объекты JPA2 аннотируются аннотациями JAXB.

Все это делается для обеспечения CRUD-интерфейса поверх модельных объектов.

конфигурация

Вот конфигурация TRANXY-JPA2-Spring-REST-CXF.xml

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
<!DOCTYPE root>
xs:noNamespaceSchemaLocation="../config/mp-config.xsd">
 <configuration>
  <conventions>
   <target-convention type="enable-updatable-code-feature" />
  </conventions>
  <model name="tranxy" version="1.0" package-root="net.sf.mp.demo">
   <data-model>
    <driver name="mysql" version="5.1.16" groupId="mysql"
     artifactId="mysql-connector-java"></driver>
    <dataSource>
     <driverClassName>org.gjt.mm.mysql.Driver</driverClassName>
     <url>jdbc:mysql://127.0.0.1:3306/tranxy</url>
     <username>root</username>
     <password>mysql</password>
    </dataSource>
    <primaryKeyPolicy oneGlobal="false" >
     <primaryKeyPolicyPattern name="autoincrementPattern"></primaryKeyPolicyPattern>
    </primaryKeyPolicy>
   </data-model>
   <business-model>
    <generation-condition>
     <condition type="exclude" startsWith="QUARTZ"></condition>
    </generation-condition>
    <business-package default="tranxy">
     <condition type="package" startsWith="trans" result="translation"></condition>
    </business-package>
    <enrichment>
     <conventions>
      <!-- manipulate the structure and entities BEFORE manipulating the
       entities -->
      <column-naming-convention type="apply-strip-column-name-suffix"
       pattern-to-strip="ID" />
      <reference-naming-convention
       type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true" />
     </conventions>
                    <entity name="language_x_translator">
                        <field name="language_id" linkReferenceAlias="translating_language" />
                        <field name="user_id" linkReferenceAlias="translator" />
                    </entity>
                    <entity name="LANGUAGE_X_SPEAKER">
                        <field name="LANGUAGE_ID" linkToTargetEntity="LANGUAGE"
                            linkToTargetField="IDLANGUAGE" linkReferenceAlias="spoken_language" />
                        <field name="user_id" linkReferenceAlias="speaker" />
                    </entity>
                    <entity name="APPLICATION">
                        <field name="TYPE">
                            <property tag="checkconstraint" alias="application_type">
                                <property name="OPENSOURCE"/>
                                <property name="COPYRIGHT" />
                            </property>
                        </field>
                    </entity>
    </enrichment>
   </business-model>
  </model>
  <targets>
             
      <target refname="REST-CXF-BSLA"
         name="default"
         fileName="mp-template-config-REST-CXF-Spring.xml"
         outputdir-root="../../DEV/latvianjug/tranxy/rest"
         templatedir-root="../../template/framework/cxf">
      </target>
 
      <target refname="BackendOnBsla"
         name="default"
         fileName="mp-template-config-JPA2-bsla.xml"
         outputdir-root="../../DEV/latvianjug/tranxy/bsla"
         templatedir-root="../../template/framework/bsla">
          <property name="add-cache-implementation" value="ehcache"></property>
      </target>
       
   <target refname="JPA2" fileName="mp-template-config-JPA2.xml"
    outputdir-root="../../DEV/latvianjug/tranxy/jpa"
        templatedir-root="../../template/framework/jpa">
 <property name="add-querydsl" value="2.1.2"></property>
 <property name="add-jpa2-implementation" value="hibernate"></property>
        <property name="add-cache-implementation" value="ehcache"></property>
        <property name="add-domain-specific-method" value="true"></property>
        <property name="add-xmlbinding" value="true"></property>
        <property name="add-xml-format" value="lowercase-hyphen"></property>
   </target>
      <target refname="MavenMaster"
         name="maven"
         fileName="mp-template-config-maven.xml"
         outputdir-root="../../DEV/latvianjug/tranxy"
         templatedir-root="../../template/framework/maven">
      </target>
 
      <target refname="CACHE-LIB" fileName="mp-template-config-CACHE-LIB.xml"
          templatedir-root="../../template/framework/cache">
      </target>
       
 <target refname="LIB" fileName="mp-template-config-bsla-LIB-features.xml"
 templatedir-root="../../template/framework/bsla">
</target>
 
      <target refname="REST-LIB"
         fileName="mp-template-config-REST-LIB.xml"
         templatedir-root="../../template/framework/rest">
      </target>
      <target refname="SPRING-LIB"
         fileName="mp-template-config-SPRING-LIB.xml"
         templatedir-root="../../template/framework/spring">
      </target>
 
  </targets>
 </configuration>
</generator-config>

Объяснения Todo

поколение

Установите файл TRANXY-JPA2-Spring-REST-CXF.xml в / mywork / config
Бег
> model-generation.cmd TRANXY-JPA2-Spring-REST-CXF.xml
Вывод идет в / dev / latvianjug / tranxy

Результирующие артефакты

Структура проекта Maven с 3 модулями

  • Слой JPA2
  • Пружинный слой DAO
  • Слой CXF

Слой JPA2 был посещен в Демо 1 и Демо 2 .

Пружинный слой DAO

Он состоит из транзакционных услуг, по одному для каждого субъекта.

Уровень CRUD DAO поверх JPA2: этот уровень называется BSLA (базовая архитектура уровня Spring).

Два интерфейса и реализации генерируются для каждого объекта
Пример для объекта перевода

Интерфейсы DAO

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * More information on minuteproject:
 * twitter @minuteproject
 *
*/
/**
 * template reference :
 * - name : BslaDaoInterfaceUML
 * - file name : BslaDaoInterfaceUML.vm
*/
package net.sf.mp.demo.tranxy.dao.face.translation;
 
import net.sf.mp.demo.tranxy.domain.translation.Translation;
import java.util.List;
import net.sf.minuteProject.architecture.bsla.bean.criteria.PaginationCriteria;
import net.sf.minuteProject.architecture.bsla.dao.face.DataAccessObject;
 
 
/**
 *
 * <p>Title: TranslationDao</p>
 *
 * <p>Description: Interface of a Data access object dealing with TranslationDao
 * persistence. It offers a set of methods which allow for saving,
 * deleting and searching translation objects</p>
 *
 */
public interface TranslationDao extends DataAccessObject {
 
    /**
     * Inserts a Translation entity
     * @param Translation translation
     */
    public void insertTranslation(Translation translation) ;
  
    /**
     * Inserts a list of Translation entity
     * @param List<Translation> translations
     */
    public void insertTranslations(List<Translation> translations) ;
         
    /**
     * Updates a Translation entity
     * @param Translation translation
     */
    public Translation updateTranslation(Translation translation) ;
 
  /**
     * Updates a Translation entity with only the attributes set into Translation.
  * The primary keys are to be set for this method to operate.
  * This is a performance friendly feature, which remove the udibiquous full load and full update when an
  * update is to be done
   * Remark: The primary keys cannot be update by this methods, nor are the attributes that must be set to null.
   * @param Translation translation
   */
    public int updateNotNullOnlyTranslation(Translation translation) ;
   
 public int updateNotNullOnlyPrototypeTranslation(Translation translation, Translation prototypeCriteria);
  
     /**
     * Saves a Translation entity
     * @param Translation translation
     */
    public void saveTranslation(Translation translation);
     
    /**
     * Deletes a Translation entity
     * @param Translation translation
     */
    public void deleteTranslation(Translation translation) ;
  
    /**
     * Loads the Translation entity which is related to an instance of
     * Translation
     * @param Long id
     * @return Translation The Translation entity
      
    public Translation loadTranslation(Long id);
*/
    /**
     * Loads the Translation entity which is related to an instance of
     * Translation
     * @param java.lang.Long Id
     * @return Translation The Translation entity
     */
    public Translation loadTranslation(java.lang.Long id);   
 
    /**
     * Loads a list of Translation entity
     * @param List<java.lang.Long> ids
     * @return List<Translation> The Translation entity
     */
    public List<Translation> loadTranslationListByTranslation (List<Translation> translations);
     
    /**
     * Loads a list of Translation entity
     * @param List<java.lang.Long> ids
     * @return List<Translation> The Translation entity
     */
    public List<Translation> loadTranslationListById(List<java.lang.Long> ids);
     
    /**
     * Loads the Translation entity which is related to an instance of
     * Translation and its dependent one to many objects
     * @param Long id
     * @return Translation The Translation entity
     */
    public Translation loadFullFirstLevelTranslation(java.lang.Long id);
     
    /**
     * Loads the Translation entity which is related to an instance of
     * Translation
     * @param Translation translation
     * @return Translation The Translation entity
     */
    public Translation loadFullFirstLevelTranslation(Translation translation);   
     
     
    /**
     * Loads the Translation entity which is related to an instance of
     * Translation and its dependent objects one to many
     * @param Long id
     * @return Translation The Translation entity
     */
    public Translation loadFullTranslation(Long id) ;
 
    /**
     * Searches a list of Translation entity based on a Translation containing Translation matching criteria
     * @param Translation translation
     * @return List<Translation>
     */
    public List<Translation> searchPrototypeTranslation(Translation translation) ;
     
    /**
     * Searches a list of Translation entity based on a list of Translation containing Translation matching criteria
     * @param List<Translation> translations
     * @return List<Translation>
     */
    public List<Translation> searchPrototypeTranslation(List<Translation> translations) ;   
      
 /**
     * Searches a list of Translation entity
     * @param Translation translation
     * @return List
     */
    public List<Translation> searchPrototypeTranslation(Translation translationPositive, Translation translationNegative) ;
         
    /**
     * Load a paginated list of Translation entity dependent of pagination criteria
     * @param PaginationCriteria paginationCriteria
     * @return List
     */
    public List<Translation> loadPaginatedTranslation (Translation translation, PaginationCriteria paginationCriteria) ;
             
}
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * More information on minuteproject:
 * twitter @minuteproject
 *
*/
/**
 * template reference :
 * - name : BslaDaoInterfaceExtendedUML
 * - file name : BslaDaoInterfaceKFUML.vm
*/
package net.sf.mp.demo.tranxy.dao.face.translation;
 
import net.sf.mp.demo.tranxy.domain.translation.Translation;
import java.util.List;
import net.sf.minuteProject.architecture.filter.data.Criteria;
import net.sf.minuteProject.architecture.bsla.dao.face.DataAccessObject;
 
/**
 *
 * <p>Title: TranslationExtDao</p>
 *
 * <p>Description: Interface of a Data access object dealing with TranslationExtDao
 * persistence. It offers extended DAO functionalities</p>
 *
 */
public interface TranslationExtDao extends DataAccessObject {
      
     /**
     * Inserts a Translation entity with cascade of its children
     * @param Translation translation
     */
    public void insertTranslationWithCascade(Translation translation) ;
     
    /**
     * Inserts a list of Translation entity with cascade of its children
     * @param List<Translation> translations
     */
    public void insertTranslationsWithCascade(List<Translation> translations) ;       
    
    /**
     * lookup Translation entity Translation, criteria and max result number
     */
    public List<Translation> lookupTranslation(Translation translation, Criteria criteria, Integer numberOfResult);
  
 public Integer updateNotNullOnlyTranslation (Translation translation, Criteria criteria);
 
 /**
  * Affect the first translation retrieved corresponding to the translation criteria.
  * Blank criteria are mapped to null.
  * If no criteria is found, null is returned.
  */
    public Translation affectTranslation (Translation translation);
     
    public Translation affectTranslationUseCache (Translation translation);
      
 /**
  * Assign the first translation retrieved corresponding to the translation criteria.
  * Blank criteria are mapped to null.
  * If no criteria is found, null is returned.
  * If there is no translation corresponding in the database. Then translation is inserted and returned with its primary key(s).
  */
    public Translation assignTranslation (Translation translation);
 
 /**
  * Assign the first translation retrieved corresponding to the mask criteria.
  * Blank criteria are mapped to null.
  * If no criteria is found, null is returned.
  * If there is no translation corresponding in the database.
  * Then translation is inserted and returned with its primary key(s).
  * Mask servers usually to set unique keys or the semantic reference
  */
    public Translation assignTranslation (Translation translation, Translation mask);
  
    public Translation assignTranslationUseCache (Translation translation);
          
    /**
    * return the first Translation entity found
    */          
    public Translation getFirstTranslation (Translation translation);
     
    /**
    * checks if the Translation entity exists
    */          
    public boolean existsTranslation (Translation translation);   
     
    public boolean existsTranslationWhereConditionsAre (Translation translation);
 
    /**
    * partial load enables to specify the fields you want to load explicitly
    */           
    public List<Translation> partialLoadTranslation(Translation translation, Translation positiveTranslation, Translation negativeTranslation);
 
    /**
    * partial load with parent entities
    * variation (list, first, distinct decorator)
    * variation2 (with cache)
    */
    public List<Translation> partialLoadWithParentTranslation(Translation translation, Translation positiveTranslation, Translation negativeTranslation);
 
    public List<Translation> partialLoadWithParentTranslationUseCache(Translation translation, Translation positiveTranslation, Translation negativeTranslation, Boolean useCache);
 
    public List<Translation> partialLoadWithParentTranslationUseCacheOnResult(Translation translation, Translation positiveTranslation, Translation negativeTranslation, Boolean useCache);
 
    /**
    * variation first
    */
    public Translation partialLoadWithParentFirstTranslation(Translation translationWhat, Translation positiveTranslation, Translation negativeTranslation);
     
    public Translation partialLoadWithParentFirstTranslationUseCache(Translation translationWhat, Translation positiveTranslation, Translation negativeTranslation, Boolean useCache);
 
    public Translation partialLoadWithParentFirstTranslationUseCacheOnResult(Translation translationWhat, Translation positiveTranslation, Translation negativeTranslation, Boolean useCache);
 
    /**
    * variation distinct
    */
    public List<Translation> getDistinctTranslation(Translation translationWhat, Translation positiveTranslation, Translation negativeTranslation);
 
    //
    public List partialLoadWithParentForBean(Object bean, Translation translation, Translation positiveTranslation, Translation negativeTranslation);
 
    /**
    * search on prototype with cache
    */
    public List<Translation> searchPrototypeWithCacheTranslation (Translation translation);
       
     
    /**
     * Searches a list of distinct Translation entity based on a Translation mask and a list of Translation containing Translation matching criteria
     * @param Translation translation
     * @param List<Translation> translations
     * @return List<Translation>
     */
    public List<Translation> searchDistinctPrototypeTranslation(Translation translationMask, List<Translation> translations) ;   
 
 public List<Translation> countDistinct (Translation whatMask, Translation whereEqCriteria);
  
 public Long count (Translation whereEqCriteria);
  
 public List<Translation> loadGraph(Translation graphMaskWhat, List<Translation> whereMask); 
  
 public List<Translation> loadGraphFromParentKey (Translation graphMaskWhat, List<Translation> parents);
  
    /**
     * generic to move after in superclass
     */
    public List<Object[]> getSQLQueryResult(String query);    
  
}

Реализации DAO

TranslationJPAImpl и TranslationJPAExtImpl (код не скопирован).

В будущем Generic DAO будет использоваться для избыточных аспектов между объектами.
Будет выполнена адаптация к Spring 3.x (т.е. больше не будет расширения JPASupport путем внедрения EntityManager)
Между тем код выше работает нормально с весной 2.5+

Пружинные конфигурации

весенне-конфигурация-Tranxy-БЭ-main.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
 
    <!-- Dao JPA -->
    <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/spring-config-JPA-Tranxy-dao.xml"/>   
 
<!--MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @JPAtranxyFactory-tranxy@-->
    <!-- hibernate config to put in an appart config file-->
    <bean id="JPAtranxyFactory" autowire="byName"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <!-- all connection information are retrieve from the persistence file-->
  <!--
   <property name="dataSource" ref="..."/>
   <property name="persistenceUnitName" value="..."/>
  -->
        <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml" />
    </bean>
<!--MP-MANAGED-UPDATABLE-ENDING-->
    <!-- Database -->
    <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/spring-config-Tranxy-database.xml"/>   
 
</beans>

весна-конфиг-Tranxy-database.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
 
 
 
    <bean id="placeHolderConfig"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location"><value>classpath:net/sf/mp/demo/tranxy/factory/spring/spring-config-Tranxy.properties</value></property>
    </bean>    
  
    <bean id="tranxyTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="JPAtranxyFactory"/>
    </bean>
 
    <!-- to get the entity manager -->
    <tx:annotation-driven transaction-manager="tranxyTransactionManager"/>
     
</beans>

весенне-конфигурация-Tranxy-BE-Главная

1
2
3
4
5
6
jdbc.tranxy.driverClassName=org.gjt.mm.mysql.Driver
jdbc.tranxy.url=jdbc:mysql://127.0.0.1:3306/tranxy
jdbc.tranxy.username=root
jdbc.tranxy.password=mysql
jdbc.tranxy.jndi=jdbc/tranxy
hibernate.dialect=org.hibernate.dialect.MySQLDialect

весна-конфиг-JPA-Tranxy-dao.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
 
<beans>
 
    <!-- Import Dao definitions for business components -->
 
   <!-- tranxy -->
   <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/tranxy/dao-JPA-Tranxy.xml"/>
   <!-- translation -->
   <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/translation/dao-JPA-Translation.xml"/>
 
    <!-- Import Ext Dao definitions for business components -->
   <!-- tranxy extended dao -->
   <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/tranxy/dao-ext-JPA-Tranxy.xml"/>
   <!-- translation extended dao -->
   <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/translation/dao-ext-JPA-Translation.xml"/>
 
</beans>

дао-JPA-Translation.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
 
    <bean id="translationDao" class="net.sf.mp.demo.tranxy.dao.impl.jpa.translation.TranslationJPAImpl" singleton="false" >
        <property name="entityManagerFactory"><ref bean="JPAtranxyFactory"/></property>
    </bean>
    <bean id="translationKeyDao" class="net.sf.mp.demo.tranxy.dao.impl.jpa.translation.TranslationKeyJPAImpl" singleton="false" >
        <property name="entityManagerFactory"><ref bean="JPAtranxyFactory"/></property>
    </bean>
    <bean id="translationRequestDao" class="net.sf.mp.demo.tranxy.dao.impl.jpa.translation.TranslationRequestJPAImpl" singleton="false" >
        <property name="entityManagerFactory"><ref bean="JPAtranxyFactory"/></property>
    </bean>
 
</beans>

То же самое для файлов dao-ext-JPA-Translation.xml, dao-ext-JPA-Tranxy.xml, dao-JPA-Tranxy.xml

Но подожди минутку … Как я могу провести юнит-тест?

Вам нужно два других артефакта, прежде чем писать свой собственный тест.

Одним из них является постоянство.xml

Еще раз? Да, со встроенным пулом соединений, поскольку поставляемый вместе со сборкой уровня JPA2 может ссылаться на источник данных JNDI (в случае, если для среды свойств установлено значение remote).
Так как он находится в / src / test / resources / META-INF, он переопределит тот, который находится в пакете JPA2.

Два — это адаптер , расширяющий AbstractTransactionalJUnit4SpringContextTests: он генерируется в / src / test / java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package net.sf.mp.demo.tranxy.dao.face;
 
import javax.sql.DataSource;
 
import org.apache.commons.lang.StringUtils;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
     "classpath:net/sf/mp/demo/tranxy/factory/spring/spring-config-Tranxy-BE-main.xml"
})
@TransactionConfiguration(transactionManager = "tranxyTransactionManager")
@Transactional
public class AdapterTranxyTestDao extends AbstractTransactionalJUnit4SpringContextTests {
 
 @Override
 @Autowired
 public void setDataSource(@Qualifier(value = "tranxyDataSource") DataSource dataSource) {
    this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
 }
...

Слой CXF

Каждый объект имеет артефакт ресурса отдыха с аннотациями JAX-RS для обеспечения доступа к CRUD. Пример с переводом

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/**
 * Copyright (c) minuteproject, minuteproject@gmail.com
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * More information on minuteproject:
 * twitter @minuteproject
 *
*/
/**
 * template reference :
 * - name : CXFSpringEntityResource
 * - file name : CXFSpringEntityResource.vm
*/
package net.sf.mp.demo.tranxy.rest.translation;
 
 
import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.io.*;
import java.sql.*;
 
import javax.servlet.http.*;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
 
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.FormParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBElement;
 
import net.sf.mp.demo.tranxy.dao.face.translation.TranslationDao;
import net.sf.mp.demo.tranxy.dao.face.translation.TranslationExtDao;
import net.sf.mp.demo.tranxy.domain.translation.Translation;
 
/**
 *
 * <p>Title: TranslationResource</p>
 *
 * <p>Description: remote interface for TranslationResource service </p>
 *
 */
@Path ("/rest/xml/translations")
@Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Consumes ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
@Service
@Transactional
public class TranslationResource  {
  
 
 @Autowired
 @Qualifier("translationDao")
 TranslationDao translationDao;
  
 @Autowired
 @Qualifier("translationExtDao")
 TranslationExtDao translationExtDao;
 
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @FIND_ALL-translation@
    @GET
    @Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public List<Translation> findAll () {
  List<Translation> r = new ArrayList<Translation>();
        List<Translation> l = translationDao.searchPrototypeTranslation(new Translation());
  for (Translation translation : l) {
   r.add(translation.flat());
  }
  return r;
    }
//MP-MANAGED-UPDATABLE-ENDING
 
//MP-MANAGED-UPDATABLE-BEGINNING-DISABLE @FIND_BY_ID-translation@
    @GET
    @Path("{id}")
    @Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) 
    public Translation findById (@PathParam ("id") java.lang.Long id) {
        Translation _translation = new Translation ();
  _translation.setId(id);
  _translation = translationExtDao.getFirstTranslation(_translation);
  if (_translation!=null) return _translation.flat();
  return new Translation ();
    }
//MP-MANAGED-UPDATABLE-ENDING
 
    @DELETE
    @Path("{id}")
    public void delete (@PathParam ("id") Long id) {
        Translation translation = new Translation ();
        translation.setId(id);
        translationDao.deleteTranslation(translation);
    }
 
    @POST
    @Produces ({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public Translation create (
        @FormParam("id") Long id,
        @FormParam("translation") String translation,
        @FormParam("language") Integer language,
        @FormParam("key") Long key,
        @FormParam("isFinal") Short isFinal,
        @FormParam("dateFinalization") Date dateFinalization,
        @FormParam("translator") Long translator,
        @Context HttpServletResponse servletResponse
        ) throws IOException {
        Translation _translation = new Translation (
           id,
           translation,
           language,
           key,
           isFinal,
           dateFinalization,
           translator);
        return save(_translation);
    }
 
    @PUT
    @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
    public Translation save(JAXBElement<Translation> jaxbTranslation) {
        Translation translation = jaxbTranslation.getValue();
        if (translation.getId()!=null)
            return translationDao.updateTranslation(translation);
        return save(translation);
    }
 
 public Translation save (Translation translation) {
  translationDao.saveTranslation(translation);
  return translation;
 }
 
 
}

И два файла для веб-приложения и источник в / src / main / resources / webapp / WEB-INF

web.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="UTF-8"?>
 
    <display-name>tranxy CXF REST</display-name>
    <description>tranxy CXF REST access</description>
 
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/application-context.xml</param-value>
    </context-param>
 
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
 
    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
 
</web-app>

Приложение-context.xml

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0" encoding="UTF-8"?>
 xsi:schemaLocation="
 
    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
     
    <context:component-scan base-package="net.sf.mp.demo.tranxy.rest"/>
 
    <import resource="classpath:net/sf/mp/demo/tranxy/factory/spring/spring-config-Tranxy-BE-main.xml"/>   
  
    <jaxrs:server id="restContainer" address="/">
        <jaxrs:serviceBeans>
   <!-- tranxy -->
   <ref bean="applicationResource"/>
   <ref bean="languageResource"/>
   <ref bean="userResource"/>
   <!-- translation -->
   <ref bean="translationResource"/>
   <ref bean="translationKeyResource"/>
   <ref bean="translationRequestResource"/>
  
   <!-- statements -->
        </jaxrs:serviceBeans>
    </jaxrs:server>
 
</beans>

Пакет, развертывание и тестирование

пакет
Перед сборкой пакета есть зависимость, поставляемая с минутным проектом mp-bsla.xyjar для установки. В / target / mp-bsla / Выполнить скрипт: maven-install.cmd / sh
Сборка:> mvn чистый пакет

Результатом является tranxyRestCxfApp.war в / rest / target

развертывание
Начать кот
Удалите tranxyRestCxfApp.war в / webapps
Существует встроенный пул соединений, поэтому на tomcat не требуется никакой настройки.

Тест

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
USE `tranxy` ;
DELETE FROM application_x_key;
DELETE FROM translation;
DELETE FROM language_x_translator;
DELETE FROM language_x_speaker;
DELETE FROM request_key;
 
DELETE FROM application;
DELETE FROM translation_key;
DELETE FROM user;
DELETE FROM language;
 
INSERT INTO application (idapplication,  name, description, type) VALUES (-1,'Porphyry', 'OS application holding environment app', 'OPENSOURCE');
INSERT INTO application (idapplication,  name, description, type) VALUES (-2,'Minuteproject', 'Minuteproject app', 'OPENSOURCE');
 
INSERT INTO user (iduser, first_name, last_name, email) VALUES (-1,'test', 'lastName', 'test@test.me');
INSERT INTO user (iduser, first_name, last_name, email) VALUES (-2,'test2', 'lastName2', 'test2@test.me');
 
INSERT INTO language (idlanguage, code, description, locale) VALUES (-1, 'FR', 'France', 'fr');
INSERT INTO language (idlanguage, code, description, locale) VALUES (-2, 'ES', 'Spanish', 'es');                                                                                              
INSERT INTO language (idlanguage, code, description, locale) VALUES (-3, 'EN', 'English', 'en');         
 
INSERT INTO language_x_translator (language_id, user_id) VALUES (-1, -1);
INSERT INTO language_x_translator (language_id, user_id) VALUES (-2, -1);
INSERT INTO language_x_speaker (language_id, user_id) VALUES (-1, -1);
INSERT INTO language_x_speaker (language_id, user_id) VALUES (-2, -1);
    
INSERT INTO language_x_translator (language_id, user_id) VALUES (-1, -2);
INSERT INTO language_x_translator (language_id, user_id) VALUES (-2, -2);
INSERT INTO language_x_translator (language_id, user_id) VALUES (-3, -2);   
 
INSERT INTO translation_key (id, key_name, description) VALUES (-1, 'msg.user.name', 'user name');
INSERT INTO translation (id, translation, language_id, key_id, is_final, date_finalization, translator_id)
VALUES (-1, 'nom', -1, -1, 1, '2012-04-04', -1);
INSERT INTO translation (id, translation, language_id, key_id, is_final, date_finalization, translator_id)
VALUES (-2, 'apellido', -1, -2, 1, CURDATE(), -1);                                                                                                              

Теперь введите
http: // localhost: 8080 / tranxyRestCxfApp / rest / xml / languages, чтобы получить все языки

Это результат

Теперь введите
http: // localhost: 8080 / tranxyRestCxfApp / rest / xml / users / -1, чтобы получить первого пользователя

Это результат

Вывод

В этой статье рассказывается, как быстро получить интерфейс CRUD REST поверх вашей модели БД. Конечно, вам может не понадобиться CRUD для всех сущностей, и вам могут понадобиться более грубые функции зерна для управления вашей моделью. Следующая статья расскажет вам, как с помощью Statement Driven Development мы можем приблизиться к Use Case.

Ссылка: RigaJUG — demo — REST CXF от нашего партнера по JCG Флориана Адлера в блоге минутного проекта .