使用Spring4.x 搭建注解式 Spring MVC + JPA 项目
在我们使用Spring3.x 系列或者是更早的系列中,大都是通过xml文件来实现配置的,大量的配置文件,和繁琐的配置。
让开发特别的不爽,在4.x 系列出来后,改变了这一状况,小编也很兴奋,就搭了一个项目体验了一下。
假设我们的基础包名为:
com.mycompany.myapp
那么小编喜欢把启动class 放在 :
com.mycompany.myapp.config 下面。
首先 基础环境必须是支持Servlet3及以上,小编使用的 Tomcat8 。
(注:在Servlet3 已经可以通过实现ServletContainerInitializer接口来配置 Filter,Servlet 和 Listener ,
Spring 进行了一些封装实现WebApplicationInitializer接口也可以达到这一效果。)
小编这里是通过三个java文件来实现的。
1。ApplicationBoot (启动类)
2。MvcConfig (mvc 的配置类)
3。RootConfig (组件配置类)
先看 ApplicationBoot 继承的是AbstractAnnotationConfigDispatcherServletInitializer
(如果需要自己控制ApplicationContext的实现类型也可以继承AbstractDispatcherServletInitializer)
public class ApplicationBoot extends
AbstractAnnotationConfigDispatcherServletInitializer{
/**
* 该方法定义的是全局的 applicationContext
* 在初始化时需要去扫描哪些带注解(如:@Configuration)的类
*/
@Override
protected Class>[] getRootConfigClasses() {
return new Class>[]{RootConfig.class};
}
/**
* 该方法定义的时Servlet级别的applicationContext
* 在初始化时需要去扫描哪些带注解(如:@Configuration)的类
*/
@Override
protected Class>[] getServletConfigClasses() {
return new Class>[]{MvcConfig.class};
}
/**
* 定义 DispatcherServlet 拦截的路径
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
那么全局的 ApplicationContext(root) 和 Servlet级的 ApplicationContext 有什么区别呢?
1.他们是父子关系,root 是 Servlet级的 父环境,也就是说 Servlet级的环境中可以访问到root环境中的实例,反之则不成立
2.项目中有几个Servlet就可以对应有几个ApplicationContext,他们都共享一个root 达到了多Servlet的实例共享
那么我们怎么来分配实例具体由哪个环境来持有呢,通常我们可以把Controller层 交给Servlet级的环境来持有,将Dao和Service层交于root来持有,当然面对项目中只有一个Servlet的情况下也可以不配置root环境(那么就需要继承AbstractDispatcherServletInitializer来精确配置)
好我们来看 MvcConfig 类
@EnableWebMvc
@Configuration
@ComponentScan("com.mycompany.myapp.controller")
public class MvcConfig extends WebMvcConfigurerAdapter{
/**
* 设置静态文件的映射关系
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
/**
* 配置视图处理技术,这里使用了jsp方式
*/
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views",".jsp");
}
/**
* 配置使用 服务器默认Servlet 来处理静态资源。DispatcherServlet 我们设置了拦截所以,所以在找静态资源的选择让default 去做。
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
/**
* 添加拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addWebRequestInterceptor(openEntityManagerInViewInterceptor());
}
/**
* 使用JPA 懒加载数据容易出现 no session 问题,可以加这个拦截器,
* 相对使用Filter 来说, 这个数据库事物是在找到相应的处理者之后才会打开
*/
@Bean
public OpenEntityManagerInViewInterceptor openEntityManagerInViewInterceptor(){
return new OpenEntityManagerInViewInterceptor();
}
}
好再看一下 RootConfig类
@Configuration
@EnableTransactionManagement
@ComponentScan({"com.mycompany.myapp.service"
,"com.mycompany.myapp.dao"})
public class RootConfig {
/**
* 配置项目的配置文件信息
*/
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer config = new PropertySourcesPlaceholderConfigurer();
config.setLocation(new ClassPathResource("META-INF/system-cnf.properties"
, AbstractMvcConfigurer.class.getClassLoader()));
return config;
}
/**
* 小编比较喜欢通过配置文件来管理数据配置信息,而没有把这部分信息配置在 persistence.xml中
*/
@Bean
public DataSource dataSource(
@Value("${db.url}")String url,
@Value("${db.user}")String username,
@Value("${db.password}")String password,
@Value("${db.driver}")String driverClassName
){
DriverManagerDataSource dataSource = new DriverManagerDataSource(url, username, password);
dataSource.setDriverClassName(driverClassName);
return dataSource;
}
/**
* JPA 实体管理工厂
*/
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource){
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setPersistenceUnitName("PU");
factory.setDataSource(dataSource);
return factory;
}
/**
* JPA 事物处理
*/
@Bean
public JpaTransactionManager jpaTransactionManager(EntityManagerFactory factory){
JpaTransactionManager manager = new JpaTransactionManager();
manager.setEntityManagerFactory(factory);
return manager;
}
/**
* 事物异常处理
*/
@Bean
public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){
return new PersistenceExceptionTranslationPostProcessor();
}
}
到这里我们还需要在 META-INF 下面放置
persistence.xml 文件
和 system-cnf.properties 的配置文件。
事务操作 仅需要在 相应方法上添加@Transactional
即可,希望小编的分享对您有所帮助。
最后贴上小编的 pom 的 jar 依赖吧。
<properties>
<org.springframework-version>4.1.7.RELEASEorg.springframework-version>
<org.aspectj-version>1.6.10org.aspectj-version>
<org.slf4j-version>1.6.6org.slf4j-version>
properties>
<dependencies>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.1version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.6.0version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>${org.springframework-version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-ormartifactId>
<version>${org.springframework-version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${org.springframework-version}version>
<exclusions>
<exclusion>
<groupId>commons-logginggroupId>
<artifactId>commons-loggingartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${org.springframework-version}version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjrtartifactId>
<version>${org.aspectj-version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>${org.slf4j-version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>jcl-over-slf4jartifactId>
<version>${org.slf4j-version}version>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>${org.slf4j-version}version>
<scope>runtimescope>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.15version>
<exclusions>
<exclusion>
<groupId>javax.mailgroupId>
<artifactId>mailartifactId>
exclusion>
<exclusion>
<groupId>javax.jmsgroupId>
<artifactId>jmsartifactId>
exclusion>
<exclusion>
<groupId>com.sun.jdmkgroupId>
<artifactId>jmxtoolsartifactId>
exclusion>
<exclusion>
<groupId>com.sun.jmxgroupId>
<artifactId>jmxriartifactId>
exclusion>
exclusions>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-entitymanagerartifactId>
<version>5.0.3.Finalversion>
<scope>compilescope>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-validatorartifactId>
<version>5.2.2.Finalversion>
dependency>
<dependency>
<groupId>javax.injectgroupId>
<artifactId>javax.injectartifactId>
<version>1version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<version>2.5version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>jsp-apiartifactId>
<version>2.1version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>1.2version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.7version>
<scope>testscope>
dependency>
dependencies>