SpringBoot是大势所趋,个人认为
-
SpringBoot简化了开发环境的搭建,包括依赖包的管理,配置的管理等;
-
便于应用微服务架构,从单体SpringBoot到SpringCloud微服务架构体系是平滑的;
本文记录个人将某个项目从SpringMVC迁移到SpringBoot所关注的几个方面。
数据库层迁移(Mybatis)
1.数据源变更
SpringBoot项目中很少使用XML配置,我们的主要工作就是将SpringMVC项目中的XML配置转化为对应的Java配置。
SpringMVC的XML数据源配置:
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
p:driverClass="${db.driverClass}" p:jdbcUrl="${db.jdbcUrl}" p:user="${db.user}"
p:password="${db.password}" p:initialPoolSize="${db.initialPoolSize}"
p:minPoolSize="${db.minPoolSize}" p:maxPoolSize="${db.maxPoolSize}"
p:preferredTestQuery="${db.preferredTestQuery}" p:testConnectionOnCheckin="true"
p:idleConnectionTestPeriod="300" destroy-method="close"/>
SpringBoot数据源配置:
@Configuration
public class DataSourceConfiguration {
@Value("${db.driverClass}")
private String jdbcDriver;
@Value("${db.jdbcUrl}")
private String jdbcUrl;
@Value("${db.user}")
private String jdbcUsername;
@Value("${db.password}")
private String jdbcPassword;
@Value("${db.preferredTestQuery}")
private String preferredTestQuery;
@Value("${db.initialPoolSize}")
private Integer initialPoolSize;
@Value("${db.minPoolSize}")
private Integer minPoolSize;
@Value("${db.maxPoolSize}")
private Integer maxPoolSize;
@Bean(destroyMethod = "close")
public ComboPooledDataSource createDataSource() throws Exception {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(jdbcDriver);
dataSource.setJdbcUrl(jdbcUrl);
dataSource.setUser(jdbcUsername);
dataSource.setPassword(jdbcPassword);
dataSource.setPreferredTestQuery(preferredTestQuery);
dataSource.setInitialPoolSize(initialPoolSize);
dataSource.setMaxPoolSize(maxPoolSize);
dataSource.setMinPoolSize(minPoolSize);
dataSource.setTestConnectionOnCheckin(true);
dataSource.setIdleConnectionTestPeriod(300);
return dataSource;
}
}
2.Mybatis的SqlSessionFactory
SpringMVC的SqlSessionFactory定义如下
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="wrappedDataSource"></property>
<property name="configLocation" value="classpath:spring/mybatis-config.xml"></property>
<property name="mapperLocations">
<array>
<value>classpath:mybatis/*.xml</value>
</array>
</property>
<!-- 分页插件 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<!-- config params as the following -->
<value>
helperDialect=mysql
</value>
</property>
</bean>
</array>
</property>
</bean>
转化为SpringBoot,需要引入mybatis的自动配置jar包,分页jar包。
在POM文件中添加如下jar包:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
并在application.properties中添加如下配置:
mybatis.config-location=classpath:mybatis-config.xml
mybatis.mapper-locations=classpath:mapper/*.xml
pagehelper.helper-dialect=mysql
SqlSessionFactory能自动找到Spring容器中的DataSource 实例。
还需要告诉Mybatis从哪个包里搜索Mapper实例,在启动Class上使用注解@MapperScan完成。
服务层迁移
服务层主要是事务的迁移,在SpringMVC中,在XML文件中定义切片,并根据特定的异常类型进行事务回滚(在这里是ServiceException)。
<aop:config>
<aop:pointcut id="txPointCutDef" expression="this(com.jhcl.ucclub.core.TransactionalAspectAwareService)"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCutDef"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="list*" read-only="true"/>
<tx:method name="search*" read-only="true"/>
<tx:method name="select*" read-only="true"/>
<tx:method name="view*" read-only="true"/>
<tx:method name="*" read-only="false" propagation="REQUIRED"
rollback-for="com.jhcl.ucclub.core.ServiceException"/>
</tx:attributes>
</tx:advice>
SpringBoot中使用Java Config完成:
@Aspect
@Configuration
public class TransationAdviceConfig {
private static final int TX_METHOD_TIMEOUT = 5;
private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.***.service.impl..*.*.*(..))";
@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public TransactionInterceptor txAdvice() {
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
RuleBasedTransactionAttribute readOnlyRule = new RuleBasedTransactionAttribute();
readOnlyRule.setReadOnly(true);
readOnlyRule.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
RuleBasedTransactionAttribute requireRule = new RuleBasedTransactionAttribute();
requireRule.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(ServiceException.class)));
requireRule.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
requireRule.setTimeout(TX_METHOD_TIMEOUT);
Map<String, TransactionAttribute> txMap = new HashMap<>();
txMap.put("add*", requireRule);
txMap.put("save*", requireRule);
txMap.put("insert*", requireRule);
txMap.put("update*", requireRule);
txMap.put("delete*", requireRule);
txMap.put("remove*", requireRule);
txMap.put("get*", readOnlyRule);
txMap.put("query*", readOnlyRule);
txMap.put("find*", readOnlyRule);
txMap.put("select*", readOnlyRule);
source.setNameMap(txMap);
TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
return txAdvice;
}
@Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}
还需要在启动Class上使用注解@EnableTransactionManagement启用事务管理。
Web层迁移
SpringMVC消息转换器以及文件上传配置:
<annotation-driven>
<message-converters >
<beans:bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<!--解决 HttpMediaTypeNotAcceptableException: Could not find acceptable representation -->
<beans:property name="supportedMediaTypes">
<beans:list>
<beans:value>text/html;charset=UTF-8</beans:value>
<beans:value>text/json;charset=UTF-8</beans:value>
<beans:value>application/json;charset=UTF-8</beans:value>
<beans:value>application/x-www-form-urlencoded;charset=UTF-8</beans:value>
<beans:value>application/x-www-form-urlencoded</beans:value>
</beans:list>
</beans:property>
</beans:bean>
</message-converters>
</annotation-driven>
<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<beans:property name="maxUploadSize" value="104857600" />
<beans:property name="maxInMemorySize" value="4096" />
<beans:property name="defaultEncoding" value="UTF-8"></beans:property>
<beans:property name="uploadTempDir" value="upload/temp"></beans:property>
</beans:bean>
SpringBoot对应的Java Config:
@Configuration
public class MvcConfiguration extends WebMvcConfigurerAdapter {
public void configureMessageConverters(List<HttpMessageConverter<?>> converters){
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
List<MediaType> list = new ArrayList<>();
list.add(MediaType.TEXT_HTML);
list.add(MediaType.APPLICATION_JSON_UTF8);
list.add(MediaType.APPLICATION_JSON);
list.add(MediaType.APPLICATION_FORM_URLENCODED);
converter.setSupportedMediaTypes(list);
converters.add(converter);
}
@Bean(name = {"multipartResolver"})
public MultipartResolver multipartResolver() throws IOException {
CommonsMultipartResolver commonsMultipartResolver=new CommonsMultipartResolver();
commonsMultipartResolver.setDefaultEncoding("UTF-8");
commonsMultipartResolver.setMaxUploadSize(10485760L);
commonsMultipartResolver.setMaxInMemorySize(4096);
commonsMultipartResolver.setUploadTempDir(new FileSystemResource("upload/temp"));
return commonsMultipartResolver;
}
}
Web.xml 配置文件迁移
-
由于注解都会被@SpringBootApplication扫描到并且加入到Spring容器中,消除了XML文件中的bean定义,所以ContextLoaderListener不需要了。
-
DispatcherServlet也不需要配置了,SpringBoot会自动配置
-
UTF-8编码过滤器改为使用配置实现:
# Charset of HTTP requests and responses. Added to the "Content-Type" header if not set explicitly.
spring.http.encoding.charset=UTF-8
# Enable http encoding support.
spring.http.encoding.enabled=true
# Force the encoding to the configured charset on HTTP requests and responses.
spring.http.encoding.force=true
- 自定义Filter在Configuration类中配置,并且可以指定顺序:
@Bean
public FilterRegistrationBean testFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
registration.addUrlPatterns("/*");
registration.addInitParameter("paramName", "paramValue");
registration.setName("MyFilter");
registration.setOrder(1);
return registration;
}
其他
- SpringBoot 2.0开始在将Java对象转换为JSON时,会自动将Date类型字段转为UTC格式,可以通知修改配置改为时间戳:
spring.jackson.serialization.write-dates-as-timestamps=true
总结
以上,便是从SpringMVC迁移到SpringBoot的一些关注点,后续还会根据情况补充更新。
(转载本站文章请注明作者和出处 湘江鸿的博客)