基于SSM的全注解模式Web项目的环境搭建
以往我们用SSM构建Web项目,需要一些配置文件,例如web.xml,spring-*.xml等等,servlet3.0+版本提供了基于注解模式的Web项目构建方式,省去了配置文件。本文主要描述了基于注解方式的Web项目环境搭建。
既然去掉了配置文件,那么我们需要编写一些配置类,来代替配置文件,构建起基本的项目环境,下面是Web项目基本环境的搭建:
import java.io.IOException;
import javax.sql.DataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import com.alibaba.druid.pool.DruidDataSource;
@Configuration
@PropertySource("classpath:configs.properties")
public class AppRootConfig {
public AppRootConfig() {
System.out.println("AppRootConfig");
}
@Bean
public DruidDataSource getDataSource(
@Value("${jdbcDriver}")String driver,
@Value("${jdbcUrl}")String url,
@Value("${jdbcUser}")String username,
@Value("${jdbcPassword}")String password){
DruidDataSource ds=new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
@Bean("sqlSessionFactory")
public SqlSessionFactoryBean getFactory(@Autowired DataSource ds) throws IOException{
SqlSessionFactoryBean factory=new SqlSessionFactoryBean();
factory.setDataSource(ds);
ResourcePatternResolver resolver=new PathMatchingResourcePatternResolver();
Resource[] mapperLocations=resolver.getResources("classpath:mapper/*.xml");
factory.setMapperLocations(mapperLocations);
return factory;
}
@Bean
public MapperScannerConfigurer getScanner(){
MapperScannerConfigurer scanner=new MapperScannerConfigurer();
scanner.setBasePackage("com.jt.**.dao");
scanner.setSqlSessionFactoryBeanName("sqlSessionFactory");
return scanner;
}
}
这里首先@Configuration表示这是一个配置类,然后加载了一个configs.properties文件,内部定义了数据库连接的相关配置。类中首先利用阿里开发的druid连接池获取数据库连接,接着基于此连接获取了Mybatis中的关键对象sqlSessionFactory,这是Spring关于Mybatis部份的整合,最后注册了一个扫描dao包的扫描器,dao包中用于存放数据持久层的接口,而扫描器扫描后,可以生成这个接口相对应的bean对象,不需要我们再调用getMapper()方法手动获取。
基本环境搭建完毕,我们需要搭建Servlet环境:
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
@ComponentScan("com.jt")
@EnableWebMvc
public class AppServletConfig extends WebMvcConfigurerAdapter{
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/pages/", ".html");
}
}
这里首先同样表明它是一个配置类,然后@ComponentScan("com.jt")表示扫描这个包下的所有组件,即包含有类似@Controller,@Configuration,@Bean等注解的部分。@EnaleWebMvc表示启用WebMvc的相关注解和默认配置。这个类继承了WebMvcConfigurerAdapter,从名字可以看出这是一个关于WebMvc配置的类,可以通过重写父类方法的方式为当前项目进行配置。类中加载了一个视图解析器,视图文件的路径是/WEB-INF/pages,文件的类型是.html文件。此外这个类中还可以通过重写addInterceptors()方法添加拦截器。
配置类准备就绪,既然作为配置类,那么肯定是要在项目启动时就生效,那么怎样让我们的配置类在服务器启动时就自动加载呢?找到下图中的文件,打开以后找到文件中的那个类org.springframework.web.SpringServletContainerInitializer,
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer) waiClass.newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
}
这个类上的注释@HandlesTypes(WebApplicationInitializer.class),服务器启动时,spring会通过这个类中的onStartup()方法加载WebApplicationInitializer这个接口及其子类,那么我们只需要写一个类实现这个接口,再把我们需要启动时加载的部分放在这个类中即可。
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class AppWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{AppRootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{AppServletConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"*.do"};
}
}
AbstractAnnotationConfigDispatcherServletInitializer 是WebApplicationInitializer接口的一个实现类,我们写了一个雷,继承了这个实现类,并重写了其中的关键方法,加载了本项目中的配置类。最后的*.do规定了客户端访问时,需要以.do结尾,才能通过前端控制器。