jackson enum 枚举转换

jackson 枚举 转换文档

参考文档:http://www.baeldung.com/jackson-serialize-enums

                  http://wiki.fasterxml.com/JacksonFeaturesSerialization

                 http://stackoverflow.com/questions/7766791/serializing-enums-with-jackson

                 http://wiki.fasterxml.com/JacksonFeaturesSerialization

                 http://forum.spring.io/forum/spring-projects/web/122861-responsebody-and-enums

 

                 spring mvc 文件上传文档

               http://www.tuicool.com/articles/iQV3mm

               http://my.oschina.net/chinamummy29/blog/288175

 

              maven pom 属性 大全

              http://www.blogjava.net/jianyue/articles/227932.html

  

 

              shiro 权限验证文档

             http://my.oschina.net/u/1448456/blog/198648#OSC_h4_5

 

             hibernate4  二级缓存,分布式缓存

             http://my.oschina.net/u/943305/blog/212402

            http://leobluewing.iteye.com/blog/2032396

           http://www.blogjava.net/sway/archive/2008/10/23/236094.html

 

              hibernate4 spring data jpa 分布式事务 jta

           http://timtang.me/blog/2012/12/25/spring-hibernate4-atomiks-jta/

            http://my.oschina.net/l1z2g9/blog/28983

          http://www.xuehuile.com/blog/3a63dbc857134bdca34b7326c266b62c.html

          http://fabiomaffioletti.me/blog/2014/04/15/distributed-transactions-multiple-databases-spring-boot-spring-data-jpa-atomikos/

        http://my.oschina.net/l1z2g9/blog/28983?catalog=56071

 

 

 

 

Use spring3.1 hibernate4 atomikos3.8 to implements JTA(XA)

Introduce to hibernate JPA integrate with spring to implements JTA.

Preparation


  • Spring3.1
  • Hibernate4
  • Atomikos3.8
  • Jetty

Dependency Library


  • transactions.jar
  • transactions-jta.jar
  • transactions-jdbc.jar
  • transactions-hibernate3.jar
  • cglib.jar (hibernate4 depends it)
  • spring related libs
  • hibernate related libs

Following is detailed configuration:


Atomikos datasource configuration, we have two datasource like:

<bean id="firstDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
	<description>first XA DataSource</description>
		<property name="uniqueResourceName">
	<value>firstDS</value>
	</property>
		<property name="xaDataSourceClassName" value="${jdbc.driver}" />
		<property name="xaProperties">
		<props>
			<prop key="user">username</prop>
			<prop key="password">password</prop>
			<prop key="serverName">127.0.0.1</prop>
			<prop key="portNumber">5432</prop>
			<prop key="databaseName">dataSource1</prop>
		</props>
	</property>
	<property name="poolSize" value="10"/>
</bean>

<bean id="secondDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
	<description>second XA DataSource</description>
	<property name="uniqueResourceName">
		<value>secondDS</value>
	</property>
	<property name="xaDataSourceClassName" value="${jdbc.driver}" />
	<property name="xaProperties">
	<props>
		<prop key="user">username</prop>
		<prop key="password">password</prop>
		<prop key="serverName">127.0.0.1</prop>
		<prop key="portNumber">5432</prop>
		<prop key="databaseName">dataSource2</prop>
	</props>
	</property>
	<property name="poolSize" value="10"/>
</bean>

Configure the spring entity manager factory

  <bean id="auditEntityManagerFactory"
          class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="firstDataSource"/>
        <property name="packagesToScan" value="mtx.audit.model"/>
        <property name="persistenceUnitName" value="first"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect"/>
            </bean>
        </property>
        <property name="jpaProperties">
            <value>
                hibernate.show_sql=true
                hibernate.format_sql=true
                hibernate.temp.use_jdbc_metadata_defaults=false
                hibernate.current_session_context_class=jta
                hibernate.connection.release_mode=on_close
                hibernate.connection.isolation=3
              	hibernate.transaction.factory_class=org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory
                hibernate.transaction.manager_lookup_class=com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup
            </value>
        </property>
   </bean>

    <bean id="contentEntityManagerFactory"
          class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       	<property name="dataSource" ref="secondDataSource"/>
        <property name="packagesToScan" value="mtx.authoring.model"/>
        <property name="persistenceUnitName" value="second"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="databasePlatform" value="org.hibernate.dialect.PostgreSQLDialect"/>
            </bean>
        </property>
        <property name="jpaProperties">
            <value>
                hibernate.show_sql=true
                hibernate.format_sql=true
                hibernate.temp.use_jdbc_metadata_defaults=false
                <!--
                hibernate.current_session_context_class=jta
                hibernate.connection.release_mode=on_close
                hibernate.connection.isolation=3
                hibernate.transaction.factory_class=org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory
                hibernate.transaction.manager_lookup_class=com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup
                 -->
            </value>
        </property>
    </bean>

Configure transaction manager

<tx:annotation-driven transaction-manager="globalTransactionManager" proxy-target-class="true" />

<bean id="globalTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
	<property name="transactionManager" ref="atomikosTransactionManager"/>
	<property name="userTransaction"  ref="atomikosUserTransaction"/>
</bean>

<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
	init-method="init" destroy-method="close">
	<description>Atomikos Transaction Manager</description>
	<property name="forceShutdown">
		<value>true</value>
	</property>
</bean>

<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
	<property name="transactionTimeout" value="300" />
</bean>

Put jta.properties file into classpath:

com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
com.atomikos.icatch.console_file_name = tm.out
com.atomikos.icatch.log_base_name = tmlog
com.atomikos.icatch.tm_unique_name = com.atomikos.spring.jdbc.tm
com.atomikos.icatch.console_log_level = INFO
com.atomikos.icatch.max_timeout=3600000

           

 

 

 

 

 

 

 

 

The resulting implementation is the following. It's worth noting that they belong to two different packages, for two main reasons:

  1. it's a logical separation that gives order to the project
  2. each repository will scan packages containing only entities that it will be going to manage
package com.at.mul.domain.customer;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;
import lombok.EqualsAndHashCode;

@Entity
@Table(name = "customer")
@Data
@EqualsAndHashCode(exclude = { "id" })
public class Customer {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;

	@Column(name = "name", nullable = false)
	private String name;

	@Column(name = "age", nullable = false)
	private Integer age;

}
package com.at.mul.domain.order;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;
import lombok.EqualsAndHashCode;

@Entity
@Table(name = "orders")
@Data
@EqualsAndHashCode(exclude = { "id" })
public class Order {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;

	@Column(name = "code", nullable = false)
	private Integer code;

	@Column(name = "quantity", nullable = false)
	private Integer quantity;

}
 See  Lombok for annotations like  @Data and  @EqualsAndHashCode

Write repositories interfaces

Also in this case it's standard, the only thing to notice is that I put the two interfaces in two different packages. The reason is explained in the next step.

package com.at.mul.repository.customer;

import org.springframework.data.jpa.repository.JpaRepository;

import com.at.mul.domain.customer.Customer;

public interface CustomerRepository extends JpaRepository<Customer, Integer> {

}
package com.at.mul.repository.order;

import org.springframework.data.jpa.repository.JpaRepository;

import com.at.mul.domain.order.Order;

public interface OrderRepository extends JpaRepository<Order, Integer> {

}

Write configuration classes

This is where it becomes interesting. The @DependsOn("transactionManager") annotation is not mandatory, but I needed this to get rid of several warnings at tests (or application) startup, like WARNING: transaction manager not running? in the logs. The next annotation @EnableJpaRepositories is more important:

  • it specifies which are the packages to scan for annotated components (repository interfaces), and in my case I wanted only repositories related to the customer (and conversely to the order).
  • it specifies which is the entity manager to be used to manage entities, in my case the customerEntityManager for customer related operations and orderEntityManager for order related operations
  • it specifies the transaction manager to be used, in my case the transactionManager defined in the MainConfig class. This needs to be the same for every@EnableJpaRepositories to get distributed transactions working
package com.at.mul;

import java.util.HashMap;

import javax.sql.DataSource;

import org.h2.jdbcx.JdbcDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

import com.at.mul.repository.customer.CustomerDatasourceProperties;
import com.atomikos.jdbc.AtomikosDataSourceBean;

@Configuration
@DependsOn("transactionManager")
@EnableJpaRepositories(basePackages = "com.at.mul.repository.customer", entityManagerFactoryRef = "customerEntityManager", transactionManagerRef = "transactionManager")
@EnableConfigurationProperties(CustomerDatasourceProperties.class)
public class CustomerConfig {

	@Autowired
	private JpaVendorAdapter jpaVendorAdapter;

	@Autowired
	private CustomerDatasourceProperties customerDatasourceProperties;

	@Bean(name = "customerDataSource", initMethod = "init", destroyMethod = "close")
	public DataSource customerDataSource() {
		JdbcDataSource h2XaDataSource = new JdbcDataSource();
		h2XaDataSource.setURL(customerDatasourceProperties.getUrl());

		AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
		xaDataSource.setXaDataSource(h2XaDataSource);
		xaDataSource.setUniqueResourceName("xads1");
		return xaDataSource;
	}

	@Bean(name = "customerEntityManager")
	@DependsOn("transactionManager")
	public LocalContainerEntityManagerFactoryBean customerEntityManager() throws Throwable {

		HashMap<String, Object> properties = new HashMap<String, Object>();
		properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
		properties.put("javax.persistence.transactionType", "JTA");

		LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
		entityManager.setJtaDataSource(customerDataSource());
		entityManager.setJpaVendorAdapter(jpaVendorAdapter);
		entityManager.setPackagesToScan("com.at.mul.domain.customer");
		entityManager.setPersistenceUnitName("customerPersistenceUnit");
		entityManager.setJpaPropertyMap(properties);
		return entityManager;
	}

}
package com.at.mul;

import java.util.HashMap;

import javax.sql.DataSource;

import org.h2.jdbcx.JdbcDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

import com.at.mul.repository.order.OrderDatasourceProperties;
import com.atomikos.jdbc.AtomikosDataSourceBean;

@Configuration
@DependsOn("transactionManager")
@EnableJpaRepositories(basePackages = "com.at.mul.repository.order", entityManagerFactoryRef = "orderEntityManager", transactionManagerRef = "transactionManager")
@EnableConfigurationProperties(OrderDatasourceProperties.class)
public class OrderConfig {

	@Autowired
	private JpaVendorAdapter jpaVendorAdapter;

	@Autowired
	private OrderDatasourceProperties orderDatasourceProperties;

	@Bean(name = "orderDataSource", initMethod = "init", destroyMethod = "close")
	public DataSource orderDataSource() {
		JdbcDataSource h2XaDataSource = new JdbcDataSource();
		h2XaDataSource.setURL(orderDatasourceProperties.getUrl());

		AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
		xaDataSource.setXaDataSource(h2XaDataSource);
		xaDataSource.setUniqueResourceName("xads2");
		return xaDataSource;
	}

	@Bean(name = "orderEntityManager")
	public LocalContainerEntityManagerFactoryBean orderEntityManager() throws Throwable {

		HashMap<String, Object> properties = new HashMap<String, Object>();
		properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
		properties.put("javax.persistence.transactionType", "JTA");

		LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
		entityManager.setJtaDataSource(orderDataSource());
		entityManager.setJpaVendorAdapter(jpaVendorAdapter);
		entityManager.setPackagesToScan("com.at.mul.domain.order");
		entityManager.setPersistenceUnitName("orderPersistenceUnit");
		entityManager.setJpaPropertyMap(properties);
		return entityManager;
	}

}

Another important thing here is the definition of the LocalContainerEntityManagerFactoryBean.

  • the @Bean annotation has a given name, that is the one specified in the @EnableJpaRepositories annotation.
  • you need to set some properties to the JpaPropertyMap, in particular you need to say that the transaction type is JTA and that the jta platform isAtomikosJtaPlatform.class.getName()
Not setting the second property was the reason why I could not get it work. As Dave Syer wrote "It seems Hibernate4 doesn't work with Atomikos out of the box", so you need to implement the class to be set as  hibernate.transaction.jta.platform property by yourself. In my opinion this is not very well documented, but fortunately Oliver Gierke found another  StackOverflow discussion about this topic. If you are using another JTA provider, you may find  this useful.

Write the AbstractJtaPlatform implementation

As said, this is the most important step, as we need to write the implementation of that class by ourselves since Hibernate does not provide it. Here is the resulting code:

package com.at.mul;

import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;

import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;

public class AtomikosJtaPlatform extends AbstractJtaPlatform {

	private static final long serialVersionUID = 1L;

	static TransactionManager transactionManager;
	static UserTransaction transaction;

	@Override
	protected TransactionManager locateTransactionManager() {
		return transactionManager;
	}

	@Override
	protected UserTransaction locateUserTransaction() {
		return transaction;
	}

}

Write the main configuration class

Also in this case it's a pretty standard class, with @EnableTransactionManagement annotation and Atomikos bean definitions. The only very important thing to notice is that we need to set AtomikosJtaPlatform.transactionManager and AtomikosJtaPlatform.transaction attributes.

package com.at.mul;

import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.jta.JtaTransactionManager;

import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;

@Configuration
@ComponentScan
@EnableTransactionManagement
public class MainConfig {

	@Bean
	public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}
	
	@Bean
	public JpaVendorAdapter jpaVendorAdapter() {
		HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
		hibernateJpaVendorAdapter.setShowSql(true);
		hibernateJpaVendorAdapter.setGenerateDdl(true);
		hibernateJpaVendorAdapter.setDatabase(Database.H2);
		return hibernateJpaVendorAdapter;
	}

	@Bean(name = "userTransaction")
	public UserTransaction userTransaction() throws Throwable {
		UserTransactionImp userTransactionImp = new UserTransactionImp();
		userTransactionImp.setTransactionTimeout(10000);
		return userTransactionImp;
	}

	@Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
	public TransactionManager atomikosTransactionManager() throws Throwable {
		UserTransactionManager userTransactionManager = new UserTransactionManager();
		userTransactionManager.setForceShutdown(false);

		AtomikosJtaPlatform.transactionManager = userTransactionManager;

		return userTransactionManager;
	}

	@Bean(name = "transactionManager")
	@DependsOn({ "userTransaction", "atomikosTransactionManager" })
	public PlatformTransactionManager transactionManager() throws Throwable {
		UserTransaction userTransaction = userTransaction();

		AtomikosJtaPlatform.transaction = userTransaction;

		TransactionManager atomikosTransactionManager = atomikosTransactionManager();
		return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值