之前項目中使用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.0</modelVersion> <groupId>io.powerx</groupId> <artifactId>springmvcconfig</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <properties> </properties> <dependencies> <!-- spring相關 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.3.9.RELEASE</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <!-- springmvc相關 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.9.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.9.RELEASE</version> </dependency> <!-- servlet配置,不配置也不影響,但是jsp會報錯 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- 加載jackson包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.7.3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.7.3</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.7.3</version> </dependency> <!-- druid數據源 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.16</version> </dependency> <!-- spring和mybatis整合 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <!-- MySQL數據庫連接驅動 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.43</version> </dependency> <!-- MyBatis框架 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.1</version> </dependency> <!-- 添加logback日志 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </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"> <!-- 數據庫字段和實體類屬性映射關系,名稱一樣的字段可以無需映射。column對應數據庫的實際字段,property對應實體類的屬性 --> <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。