之前项目中使用ssm框架大多是基于xml的方式,spring3.0以后就提供java config的模式来构建项目,并且也推荐使用这种方式,自从接触过springboot后,深深感受到这种纯java配置的便利,但是springboot默认为我们引入好多jar和配置,使得项目变得很重,因此决定自己动手搭建一个无xml的ssm项目。
开发环境
我的开发环境如下:
web服务器:tomcat8
开发工具:STS
JDK版本:1.8
项目构建工具:maven
搭建过程
1、首先引入相关依赖
pom文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0modelVersion> <groupId>io.powerxgroupId> <artifactId>springmvcconfigartifactId> <packaging>warpackaging> <version>0.0.1-SNAPSHOTversion> <properties> properties> <dependencies> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-contextartifactId> <version>4.3.9.RELEASEversion> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-aopartifactId> <version>4.3.9.RELEASEversion> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-coreartifactId> <version>4.3.9.RELEASEversion> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-beansartifactId> <version>4.3.9.RELEASEversion> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-jdbcartifactId> <version>4.3.9.RELEASEversion> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-txartifactId> <version>4.3.9.RELEASEversion> dependency> <dependency> <groupId>commons-logginggroupId> <artifactId>commons-loggingartifactId> <version>1.2version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-webartifactId> <version>4.3.9.RELEASEversion> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-webmvcartifactId> <version>4.3.9.RELEASEversion> dependency> <dependency> <groupId>javax.servletgroupId> <artifactId>javax.servlet-apiartifactId> <version>3.1.0version> dependency> <dependency> <groupId>javax.servletgroupId> <artifactId>jstlartifactId> <version>1.2version> dependency> <dependency> <groupId>com.fasterxml.jackson.coregroupId> <artifactId>jackson-coreartifactId> <version>2.7.3version> dependency> <dependency> <groupId>com.fasterxml.jackson.coregroupId> <artifactId>jackson-databindartifactId> <version>2.7.3version> dependency> <dependency> <groupId>com.fasterxml.jackson.coregroupId> <artifactId>jackson-annotationsartifactId> <version>2.7.3version> dependency> <dependency> <groupId>com.alibabagroupId> <artifactId>druidartifactId> <version>1.0.16version> dependency> <dependency> <groupId>org.mybatisgroupId> <artifactId>mybatis-springartifactId> <version>1.3.0version> dependency> <dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>5.1.43version> dependency> <dependency> <groupId>org.mybatisgroupId> <artifactId>mybatisartifactId> <version>3.4.1version> dependency> <dependency> <groupId>org.slf4jgroupId> <artifactId>slf4j-apiartifactId> <version>1.7.25version> dependency> <dependency> <groupId>ch.qos.logbackgroupId> <artifactId>logback-classicartifactId> <version>1.2.3version> dependency> <dependency> <groupId>ch.qos.logbackgroupId> <artifactId>logback-coreartifactId> <version>1.2.3version> dependency> dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.pluginsgroupId> <artifactId>maven-compiler-pluginartifactId> <configuration> <source>1.8source> <target>1.8target> configuration> plugin> plugins> build> project>
2、编写配置文件
MyWebAppInitializer继承AbstractAnnotationConfigDispatcherServletInitializer,并重写其中的方法(另外一种方式是MyWebAppInitializer直接实现WebApplicationInitializer接口,不过会复杂一点),它是我们程序的入口,web容器启动后会调其中相关的方法从而启动整个应用。主要实现3个方法:getRootConfigClasses,负责加载spring容器,本例中我们只加载了RootConfig类,其它一些spring相关配置类也可以在这里加载;getServletConfigClasses,加载springmvc容器,本例中我们加载了MvcConfig;getServletMappings,设置映射的路径。配置代码如下:
MyWebAppInitializer.java
package powerx.io.config; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class>[] getRootConfigClasses() { return new Class>[]{RootConfig.class}; } protected Class>[] getServletConfigClasses() { return new Class>[]{MvcConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } }
RootConfig.java
package powerx.io.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.context.annotation.Import; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @Configuration @EnableTransactionManagement //开启事务支持 @Import(DruidDataSourceConfig.class)//导入数据源的配置 @ComponentScan(basePackages = {"powerx.io.service","powerx.io.dao","powerx.io.config"}, excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class)}) public class RootConfig { }
MvcConfig.java
package powerx.io.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.InternalResourceViewResolver; @Configuration @EnableWebMvc @ComponentScan("powerx.io.controller") public class MvcConfig extends WebMvcConfigurerAdapter{ @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("index"); super.addViewControllers(registry); } //配置jsp视图 @Bean public ViewResolver viewResolver(){ InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/"); resolver.setSuffix(".jsp"); resolver.setExposeContextBeansAsAttributes(true); return resolver; } //配置静态资源处理 @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable();//将静态资源的请求转发到servlet容器中默认的servlet上 } }
DruidDataSourceConfig.java
package powerx.io.config; import java.io.IOException; import java.sql.SQLException; import javax.sql.DataSource; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; 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.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import com.alibaba.druid.pool.DruidDataSource; @Configuration @PropertySource("classpath:jdbc.properties") @MapperScan(basePackages="powerx.io.dao") public class DruidDataSourceConfig{ @Value("${spring.datasource.url}") private String dbUrl; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; @Value("${spring.datasource.driverClassName}") private String driverClassName; @Value("${spring.datasource.initialSize}") private int initialSize; @Value("${spring.datasource.minIdle}") private int minIdle; @Value("${spring.datasource.maxActive}") private int maxActive; @Value("${spring.datasource.maxWait}") private int maxWait; @Value("${spring.datasource.timeBetweenEvictionRunsMillis}") private int timeBetweenEvictionRunsMillis; @Value("${spring.datasource.minEvictableIdleTimeMillis}") private int minEvictableIdleTimeMillis; @Value("${spring.datasource.validationQuery}") private String validationQuery; @Value("${spring.datasource.testWhileIdle}") private boolean testWhileIdle; @Value("${spring.datasource.testOnBorrow}") private boolean testOnBorrow; @Value("${spring.datasource.testOnReturn}") private boolean testOnReturn; @Value("${spring.datasource.poolPreparedStatements}") private boolean poolPreparedStatements; @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}") private int maxPoolPreparedStatementPerConnectionSize; @Value("${spring.datasource.filters}") private String filters; @Value("{spring.datasource.connectionProperties}") private String connectionProperties; @Bean //声明其为Bean实例 public DataSource dataSource(){ DruidDataSource datasource = new DruidDataSource(); datasource.setUrl(this.dbUrl); datasource.setUsername(username); datasource.setPassword(password); datasource.setDriverClassName(driverClassName); datasource.setInitialSize(initialSize); datasource.setMinIdle(minIdle); datasource.setMaxActive(maxActive); datasource.setMaxWait(maxWait); datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); datasource.setValidationQuery(validationQuery); datasource.setTestWhileIdle(testWhileIdle); datasource.setTestOnBorrow(testOnBorrow); datasource.setTestOnReturn(testOnReturn); datasource.setPoolPreparedStatements(poolPreparedStatements); datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); try { datasource.setFilters(filters); } catch (SQLException e) { } datasource.setConnectionProperties(connectionProperties); return datasource; } //mybatis的配置 @Bean public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException{ ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();//mybatis-plus插件类 sqlSessionFactoryBean.setDataSource(dataSource());//数据源 sqlSessionFactoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath:mappers/*.xml")); sqlSessionFactoryBean.setTypeAliasesPackage("powerx.io.model");//别名,让*Mpper.xml实体类映射可以不加上具体包名 return sqlSessionFactoryBean; } }
3、配置数据源和mapper映射文件等
jdbc.properties
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.driverClassName=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/testssm spring.datasource.username=root spring.datasource.password=root spring.datasource.initialSize=5 spring.datasource.minIdle=5 spring.datasource.maxActive=20 spring.datasource.maxWait=60000 spring.datasource.timeBetweenEvictionRunsMillis=60000 spring.datasource.minEvictableIdleTimeMillis=300000 spring.datasource.validationQuery=SELECT 1 FROM DUAL spring.datasource.testWhileIdle=true spring.datasource.testOnBorrow=false spring.datasource.testOnReturn=false spring.datasource.poolPreparedStatements=true spring.datasource.maxPoolPreparedStatementPerConnectionSize=20 spring.datasource.filters=stat spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
UserMapper.xml
xml version="1.0" encoding="UTF-8" ?> DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="powerx.io.dao.UserDao"> <resultMap type="User" id="UserResult"> <result column="USER_NAME" property="userName" /> <result column="USER_PWD" property="userPwd" /> resultMap> <select id="findByName" parameterType="String" resultMap="UserResult"> SELECT USER_NAME,USER_PWD FROM USER WHERE USER_NAME=#{userName} select> <insert id="insertUser" parameterType="powerx.io.model.User"> INSERT INTO USER(USER_NAME,USER_PWD) VALUES(#{userName},#{userPwd}) insert> mapper>
User.java
package powerx.io.model; public class User { private String userName; private String userPwd; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPwd() { return userPwd; } public void setUserPwd(String userPwd) { this.userPwd = userPwd; } }
UserDao.java
package powerx.io.dao; import powerx.io.model.User; public interface UserDao { User findByName(String userName); int insertUser(User user); }
4、控制层和service层
UserService.java
package powerx.io.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import powerx.io.dao.UserDao; import powerx.io.model.User; @Service public class UserService { @Autowired private UserDao userDao; public Object findByName(String userName) { return userDao.findByName(userName); } @Transactional public int insertUser(User user) { //测试事务是否起作用 userDao.insertUser(user); return userDao.insertUser(user); } }
UserContoller.java
package powerx.io.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import powerx.io.model.User; import powerx.io.service.UserService; @Controller public class UserContoller { public static Logger logger = LoggerFactory.getLogger("monitor"); @Autowired private UserService userService; @ResponseBody @RequestMapping("/get") public Object getData(String userName) { logger.info("获取用户信息"); return userService.findByName(userName); } @ResponseBody @RequestMapping("/insert") public Object insert(User user) { logger.info("添加用户"); return userService.insertUser(user); } }
5、项目结构图
总结
写完代码,在往tomcat中部署运行的时候遇到了一个问题,tomcat启动失败,报了一大堆异常,其中一个是java.util.zip.ZipException: invalid LOC header (bad signature),从网上找了一大堆答案,基本肯定是依赖的jar包不完整造成的,但是我搜索了一下maven仓库,删除了所有in_progress的包,依然不行,无奈只能一个一个的排除,浪费了好久时间,最后查出原因是因为mysql的包没有下载完整,但是依然是一个.jar结尾的文件,只不过大小不对,所以在此记录一下,以后在遇到tomcat启动失败问题,一定要细心排查所依赖的jar。
至此,整个ssm框架搭建完毕,在其中我加入了事务控制和日志管理,基本上可以作为一个生产项目的基础demo。项目代码基本上都以贴上,我也上传到了码云上面,方便自己使用,地址:https://gitee.com/hehang_com/ssm.git。