與SSH(Struts/Spring/Hibernate/)同樣,Spring+SpringMVC+MyBatis也有一個簡稱SSM,Spring實現業務對象管理,Spring MVC負責請求的轉發和視圖管理, MyBatis做爲數據對象持久化引擎。這樣搭配的優勢是:輕量、自由度高、Spring與Spring MVC契合度更好。經過一個圖書管理示例完成SSM框架的集成,能夠將前面學習過的一些內容整合起來,使用到的知識包含:Spring、Spring MVC、MyBatis、JSR303校驗、分頁、文件上傳、路徑處理等。html
說明:本文只是爲了講解SSM在IDEA中的集成方法,若是您想了解更加詳細的內容,請參考本人的另外一篇博客內容:Spring MVC 學習總結(六)——Spring+Spring MVC+MyBatis框架集成前端
1、新建一個基於Maven的Web項目
1.一、建立一個簡單的項目,這裏不使用模板。以下圖所示:java
1.二、填寫好包名、項目名以下圖所示:jquery
1.三、將項目轉換成web項目git
轉換成功:程序員
1.四、項目建立好後添加依賴包,方法有兩種,一種直接使用maven,一種手動添加。github
使用maven:web
<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.tax</groupId> <artifactId>ssm</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.3.0.RELEASE</spring.version> </properties> <dependencies> <!--Spring框架核心庫 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring MVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!-- aspectJ AOP 織入器 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.9</version> </dependency> <!--mybatis-spring適配器 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <!--Spring java數據庫訪問包,在本例中主要用於提供數據源 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!--log4j日誌包 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.6.1</version> </dependency> <!-- mybatis ORM框架 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.1</version> </dependency> <!-- JUnit單元測試工具 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> <!--c3p0 鏈接池 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <!-- JSTL --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- Servlet核心包 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <!--JSP --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.1</version> <scope>provided</scope> </dependency> </dependencies> </project>
手動添加:面試
找到要依賴的全部包
ok後關閉結構
無論使用何總方法,這裏的Oracle數據庫驅動都要手動添加。
1.五、Idea整合Tomcat
選擇項目右上角的「Edit Configurations」
添加tomcat
設置參數
設置應用上下文
添加輸出目錄
1.六、將依賴包添加到Web-Inf目錄下
到這裏項目就建立完成了。
2、建立數據庫與表
打開Oracle數據庫,建立一個表,這裏以Book表爲例,一個用於存放圖書的表,共5個字段id表示編號,title表示圖書名稱,typename表示圖書類型,price表示價格,state表示供出狀態。SQL腳本以下:
--圖書表 drop table book create table book ( id int not null primary key, --編號 title varchar2(128) not null unique, --書名 typename varchar2(128) not null, --類型 price numeric(10,2) default(0), --價格 state varchar2(10) default('未借出') --狀態 ) -- 序列 drop sequence seq_book_id create sequence seq_book_id minvalue 9 maxvalue 9999999999999999999999999999 start with 69 increment by 1 cache 20; --添加圖書 insert into book(id,title,Typename,Price,State) select 1,'零基礎學Java(全綵版)','計算機',50.60,'未借出' from dual union select 2,'輕量級Java EE企業應用實戰','軟件工程',85.30,'未借出' from dual union select 3,'Java併發編程的藝術','軟件工程',45.40,'未借出' from dual union select 4,'實戰Java高併發程序設計','軟件開發',48.70,'未借出' from dual union select 5,'Java程序員面試筆試寶典','神話',38.50,'已借出' from dual union select 6,'Java Web從入門到精通','計算機',71.00,'未借出' from dual union select 7,'Java編程思想(第4版)','計算機',70.10,'已借出' from dual union select 8,'深刻理解JAVA虛擬機','神話',65.00,'未借出' from dual union select 9,'從零開始寫Java Web框架','計算機',63.20,'已借出' from dual --sql select id, title, typename, price, state from book where id=1; commit; select seq_book_id.nextval from dual; insert into book (id, title, typename, price, state) values (seq_book_id.nextval, 'testbook', '計算機', 99.8, '未借出'); update book set title=#{title},typename=#{typename},price=#{price},state=#{state} where id=#{id} delete from book where id=#{id}
表結構以下所示:
測試數據:
3、添加依賴包
項目主要依賴的jar包有Spring核心包、Spring AOP包、Spring MVC包、MyBatis ORM包、MyBatis-Spring適配包、JSTL、JUnit、Log4j2等,具體的pom.xml文件以下:
<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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zhangguo</groupId> <artifactId>SSMall</artifactId> <version>0.0.3</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.3.0.RELEASE</spring.version> </properties> <dependencies> <!--Spring框架核心庫 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring MVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!-- aspectJ AOP 織入器 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.9</version> </dependency> <!--mybatis-spring適配器 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency> <!--Spring java數據庫訪問包,在本例中主要用於提供數據源 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!--Oracle數據庫驅動 --> <dependency> <groupId>Oracle</groupId> <artifactId>Oracle-connector-java</artifactId> <version>5.1.38</version> </dependency> <!--log4j日誌包 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.6.1</version> </dependency> <!-- mybatis ORM框架 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.1</version> </dependency> <!-- JUnit單元測試工具 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> </dependency> <!--c3p0 鏈接池 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <!-- JSTL --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- Servlet核心包 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <!--JSP --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.1</version> <scope>provided</scope> </dependency> <!-- jackson --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.5.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.5.2</version> </dependency> <!--JSR303 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.2.2.Final</version> </dependency> <!--文件上傳 --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <!-- FreeMarker --> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</version> </dependency> </dependencies> </project>
若是是第一次依賴相關的包,則須要下載時間,請耐心等待,若是下載失敗請手動下載(http://search.maven.org/)後複製到本地的資源庫中。依賴後的項目結果以下:
4、新建POJO實體層
爲了實現與數據庫中的books表進行關係映射新建一個Book圖書類,具體代碼以下:
package com.tax.model; /**圖書 POJO*/ public class Book { private int id; //編號 private String title; //標題 private String typename; //類型 private Double price; //價格 private String state; //狀態 //屬性 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getTypename() { return typename; } public void setTypename(String typename) { this.typename = typename; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } public String getState() { return state; } public void setState(String state) { this.state = state; } }
完成後的界面
5、新建MyBatis SQL映射層
這個項目中咱們採用接口與註解結合的形式完成關係與對象間的映射,在接口中定義一些數據訪問的方法,接口以下:
package com.tax.dao; import com.tax.model.Book; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import java.util.List; /**圖書數據訪問接口*/ public interface IBookDao { /**得到全部圖書*/ @Select("select id, title, typename, price, state from book") public List<Book> getAllBooks(); /**得到單個圖書對象經過編號*/ @Select("select id, title, typename, price, state from book where id=#{id}") public Book getBookById(int id); /**添加*/ @Insert("insert into Book(id, title, typename, price, state) values(seq_book_id.nextval,#{title}, #{typename}, #{price}, #{state})") public int add(Book entity); /**編輯*/ @Update("update Book set title=#{title}, typename=#{typename}, price=#{price}, state=#{state} where id=#{id}") public int edit(Book entity); /**刪除*/ @Delete("delete from Book where id=#{id}") public int delete(int id); }
結果
6、JUnit測試數據訪問(非必要)
爲了保證數據訪問正常,使用JUnit進行單元測試,在另外一個源代碼目錄src/test/java下添加一個名爲TestBook的測試用例,編寫完成的測試用例以下:
package com.tax.test; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import com.tax.entities.Book; import com.tax.mapper.BookDAO; import junit.framework.Assert; public class TestBook{ @Test public void getBookPagerTest() { int skip=4; int size=2; SqlSession session=MyBatisUtil.getSession(); try { BookDAO bookdao=session.getMapper(BookDAO.class); List<Book> Book=bookdao.getBookPager(skip, size); Assert.assertEquals(2, Book.size()); } finally { session.close(); } } @Test public void getBookByIdTest() { SqlSession session=MyBatisUtil.getSession(); try { BookDAO bookdao=session.getMapper(BookDAO.class); Book Book=bookdao.getBookById(1); Assert.assertEquals(1, Book.getId()); } finally { session.close(); } } @Test public void getBookCountTest() { SqlSession session=MyBatisUtil.getSession(); try { BookDAO bookdao=session.getMapper(BookDAO.class); Assert.assertEquals(9, bookdao.getBookCount()); } finally { session.close(); } } @Test public void insertTest() { SqlSession session=MyBatisUtil.getSession(); try { Book entity=new Book(); entity.setName("正宗無錫陽山水蜜桃新鮮水果水密桃12個6斤裝江浙滬皖順豐包郵"); entity.setPrice(108); entity.setPicture("nopic.jpg"); BookDAO bookdao=session.getMapper(BookDAO.class); Assert.assertEquals(1, bookdao.insert(entity)); } finally { session.close(); } } @Test public void deleteTest() { SqlSession session=MyBatisUtil.getSession(); try { BookDAO bookdao=session.getMapper(BookDAO.class); Assert.assertEquals(1, bookdao.delete(12)); } finally { session.close(); } } @Test public void update() { SqlSession session=MyBatisUtil.getSession(); try { BookDAO bookdao=session.getMapper(BookDAO.class); Book entity=bookdao.getBookById(12); entity.setName("正宗無錫陽山水蜜桃新鮮水果水密桃12個6斤裝"); entity.setPrice(107); entity.setPicture("nopicture.jpg"); Assert.assertEquals(1, bookdao.update(entity)); } finally { session.close(); } } }
MyBatis訪問數據庫的工具類以下:
package com.tax.test; import java.io.InputStream; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public abstract class MyBatisUtil { public static SqlSessionFactory getSqlSessionFactory(){ // 得到環境配置文件流 InputStream config = MyBatisUtil.class.getClassLoader().getResourceAsStream("MyBatisCfg.xml"); // 建立sql會話工廠 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config); return factory; } //得到會話 public static SqlSession getSession(){ return getSqlSessionFactory().openSession(true); } /** * 得到得sql會話 * @param isAutoCommit 是否自動提交,若是爲false則須要sqlSession.commit();rollback(); * @return sql會話 */ public static SqlSession getSession(boolean isAutoCommit){ return getSqlSessionFactory().openSession(isAutoCommit); } }
MyBatis配置文件MyBatisCfg.xml以下所示:
配置文件中使用到了db.properties屬性文件,該文件用於存放數據庫鏈接信息,文件內容以下:
#Oracle Oracle.driver=com.Oracle.jdbc.Driver Oracle.url=jdbc:Oracle://localhost:3306/db1 Oracle.uid=root Oracle.password=root
運行測試,一切正常,測試結果以下:
這裏須要注意的是MyBatis配置文件的內容在後面與Spring整合後是會變化的,使用JUnit測試並未使用到Spring框架。
7、完成Spring整合MyBatis配置
7.一、在源代碼的根目錄下修改db.properties文件,用於存放數據庫鏈接信息,文件內容以下:
#Oracle Oracle.driver=oracle.jdbc.driver.OracleDriver Oracle.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl Oracle.uid=tax Oracle.password=orcl Oracle.acquireIncrement=5 Oracle.initialPoolSize=10 Oracle.minPoolSize=5 Oracle.maxPoolSize=20
7.二、在源代碼的resource目錄下新建 applicationContext.xml文件,用於整合MyBatis與Spring,很是關鍵,具體的內容以下:
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <!--1 引入屬性文件,在配置中佔位使用 --> <context:property-placeholder location="classpath*:db.properties" /> <!--2 配置C3P0數據源 --> <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <!--驅動類名 --> <property name="driverClass" value="${Oracle.driver}" /> <!-- url --> <property name="jdbcUrl" value="${Oracle.url}" /> <!-- 用戶名 --> <property name="user" value="${Oracle.uid}" /> <!-- 密碼 --> <property name="password" value="${Oracle.password}" /> <!-- 當鏈接池中的鏈接耗盡的時候c3p0一次同時獲取的鏈接數 --> <property name="acquireIncrement" value="${Oracle.acquireIncrement}"></property> <!-- 初始鏈接池大小 --> <property name="initialPoolSize" value="${Oracle.initialPoolSize}"></property> <!-- 鏈接池中鏈接最小個數 --> <property name="minPoolSize" value="${Oracle.minPoolSize}"></property> <!-- 鏈接池中鏈接最大個數 --> <property name="maxPoolSize" value="${Oracle.maxPoolSize}"></property> </bean> <!--3 會話工廠bean sqlSessionFactoryBean --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 配置文件路徑 --> <property name="configLocation" value="classpath:MyBatisCfg.xml"></property> <!-- 數據源 --> <property name="dataSource" ref="datasource"></property> <!-- sql映射文件路徑 --> <!--<property name="mapperLocations" value="classpath*:com/tax/dao/*Mapper.xml"></property>--> </bean> <!--4 自動掃描對象關係映射 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!--指定會話工廠,若是當前上下文中只定義了一個則該屬性可省去 --> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> <!-- 指定要自動掃描接口的基礎包,實現接口 --> <property name="basePackage" value="com.tax.dao"></property> </bean> <!--5 聲明式事務管理 --> <!--定義事物管理器,由spring管理事務 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="datasource"></property> </bean> <!--支持註解驅動的事務管理,指定事務管理器 --> <tx:annotation-driven transaction-manager="transactionManager" /> <!--6 容器自動掃描IOC組件 --> <context:component-scan base-package="com.tax"></context:component-scan> <!--7 aspectj支持自動代理實現AOP功能 --> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> </beans>
從配置文件中能夠看出第3點會話工廠配置中指定了MyBatis配置文件的位置與名稱,其實也能夠省去,在這裏能夠經過屬性配置好。但我的認爲當多個框架整合在一塊兒時最後將配置文件分開,便於修改。修改後的MyBatisCfg.xml文件內容以下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="db.properties"></properties> <settings> <!--指定mybatis使用日誌組件 --> <setting name="logImpl" value="LOG4J2" /> <!--開啓全局的二級緩存 --> <setting name="cacheEnabled" value="false" /> <!--開啓延時加載,若是有關聯關係,則默認不會獲取數據 延遲加載的全局開關。當開啓時,全部關聯對象都會延遲加載。 特定關聯關係中可經過設置fetchType屬性來覆蓋該項的開關狀態。 在association中指定fetchType="eager(當即)" 或者 lazy(延遲) 默認:false --> <setting name="lazyLoadingEnabled" value="true" /> <!--true時,對任意延遲屬性的調用會使帶有延遲加載屬性的對象完整加載; false,每種屬性將會按需加載。 默認爲:true--> <setting name="aggressiveLazyLoading" value="false" /> </settings> <typeAliases> <package name="com.tax.model" /> </typeAliases> </configuration>
中間有一大段註釋了,是由於MyBatis-Spring適配器已完成了這部份內容的工做,註釋不刪除的緣由是由於JUnit測試時還要使用,其它也可使用兩個不一樣的文件。
8、配置web.xml加載Spring容器與MVC
修改web.xml文件,註冊加載Spring容器所需的監聽器;註冊Spring MVC前置控制器Servlet,中間還設置了Servlet3.0上傳所需的參數;添加了一個全局的編碼過濾器。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <listener> <description>Spring容器加載監聽器</description> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <description>設置Spring加載時的配置文件位置,默認位置在WEB-INF/lib目錄下</description> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext.xml</param-value> </context-param> <!--Spring MVC 前置Servlet,中心控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <!--Spring MVC配置文件路徑 --> <param-value>classpath*:springmvc-servlet.xml</param-value> </init-param> <!-- 啓動動優先級,越小越早加載 --> <load-on-startup>1</load-on-startup> <!--Servlet3.0以上文件上傳配置 --> <multipart-config> <!--上傳文件的最大限制5MB --> <max-file-size>5242880</max-file-size> <!--請求的最大限制20MB --> <max-request-size>20971520</max-request-size> <!--當文件的大小超過臨界值時將寫入磁盤 --> <file-size-threshold>0</file-size-threshold> </multipart-config> </servlet> <!-- Servlet訪問的路徑映射,全部的訪問都必須通過調度用的前置控制品 --> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--編碼過濾器 --> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <!-- 路徑映射 --> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
在src/main/java源代碼目錄下添加applicationContext.xml文件,用於配置Spring,內容在上一節中已列出。
在src/main/java源代碼目錄下添加Spring MVC配置文件springmvc-servlet.xml,文件內容以下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd"> <!-- 自動掃描包,實現支持註解的IOC --> <context:component-scan base-package="com.tax" /> <!-- Spring MVC不處理靜態資源 --> <mvc:default-servlet-handler /> <!-- 支持mvc註解驅動 --> <mvc:annotation-driven enable-matrix-variables="true" /> <!-- 配置映射媒體類型的策略 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"> <property name="removeSemicolonContent" value="false" /> </bean> <!-- 內部視圖解析器,JSP與JSTL模板 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!--指定視圖渲染類 --> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <!--自動添加到路徑中的前綴 --> <property name="prefix" value="/WEB-INF/views/" /> <!--自動添加到路徑中的後綴 --> <property name="suffix" value=".jsp" /> <!--設置全部視圖的內容類型,若是視圖自己設置內容類型視圖類能夠忽略 --> <property name="contentType" value="text/html;charset=UTF-8" /> <!-- 優先級,越小越前 --> <property name="order" value="1" /> </bean> <!--文件上傳解析器 --> <!--Spring MVC默認不能識別multipart格式的文件內容 --> <bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"> </bean> </beans>
9、建立服務層
在包com.tax.service下添加IBookService.java文件,該文件是一個服務接口,內容以下:
package com.tax.service; import com.tax.model.Book; import java.util.List; /**圖書業務接口*/ public interface IBookService { /**得到全部圖書*/ public List<Book> getAllBooks(); /**得到單個圖書對象經過編號*/ public Book getBookById(int id); /**添加*/ public int add(Book entity); /**編輯*/ public int edit(Book entity); /**刪除*/ public int delete(int id); }
在包com.tax.service下添加類BookService.java,實現接口BookService,用於完成圖書業務邏輯,因爲是示例代碼因此比較空;中間使用了兩個註解一個是@Service,用於提供給須要服務的類自動裝配,當Spring IOC容器啓動時被掃描到該類型會自動添加實例到Spring容器中;另外一個註解是@Resource用於完成自動裝配功能,在Spring容器中找到BookDAO類型的對象,代碼以下:
package com.tax.service; import com.tax.dao.IBookDao; import com.tax.model.Book; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /**圖書業務*/ @Service public class BookService implements IBookService { @Autowired IBookDao bookDao; public List<Book> getAllBooks() { return bookDao.getAllBooks(); } public Book getBookById(int id) { return bookDao.getBookById(id); } public int add(Book entity) { return bookDao.add(entity); } public int edit(Book entity) { return bookDao.edit(entity); } public int delete(int id) { return bookDao.delete(id); } }
10、完成圖書管理功能
10.一、圖書列表
定義BookController控制器,映射訪問路徑,須要使用到的圖書服務使用自動裝配完成,代碼以下:
package com.tax.controller; import com.tax.service.IBookService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import javax.annotation.Resource; /**圖書控制器*/ @Controller @RequestMapping("/Book") public class BookController { @Resource IBookService bookService; @RequestMapping("/list") public String list(Model model){ //得到全部的圖書帶到頁面中 model.addAttribute("books",bookService.getAllBooks()); return "book/list"; } }
在views/jstl/Book目錄下添加視圖list.jsp頁面,頁面的內容以下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>圖書管理</title> <meta charset="UTF-8"/> </head> <body> <h2>圖書管理</h2> <table width="100%" id="tab" border="1"> <tr> <td>編號</td> <td>書名</td> <td>類型</td> <td>價格</td> <td>狀態</td> <td>操做</td> </tr> <c:forEach var="book" items="${books}"> <tr> <td>${book.id}</td> <td>${book.title}</td> <td>${book.typename}</td> <td>${book.price}</td> <td>${book.state}</td> <td><a href="#">刪除</a> | <a href="#">編輯</a></td> </tr> </c:forEach> </table> </body> </html>
測試運行結果:
11.二、刪除與多刪除功能
修改業務層接口與實現:
IBookService:
package com.tax.service; import com.tax.model.Book; import java.util.List; /**圖書業務接口*/ public interface IBookService { /**得到全部圖書*/ public List<Book> getAllBooks(); /**得到單個圖書對象經過編號*/ public Book getBookById(int id); /**添加*/ public int add(Book entity); /**編輯*/ public int edit(Book entity); /**刪除*/ public int delete(int id); /**多刪除*/ public int delete(int[] ids); }
BookService:
package com.tax.service; import com.tax.dao.IBookDao; import com.tax.model.Book; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /**圖書業務*/ @Service public class BookService implements IBookService { @Autowired IBookDao bookDao; public List<Book> getAllBooks() { return bookDao.getAllBooks(); } public Book getBookById(int id) { return bookDao.getBookById(id); } public int add(Book entity) { return bookDao.add(entity); } public int edit(Book entity) { return bookDao.edit(entity); } public int delete(int id) { return bookDao.delete(id); } //多刪除,重載 public int delete(int[] ids) { int rows=0; for (Integer id:ids) { //遍歷全部的編號 rows+=delete(id); //調用單刪除功能,累計刪除行數 } return rows; } }
爲了實現刪除與多刪除功能,修改控制器,增長2個action,delete請求處理方法用於刪除單個記錄,id是路徑變量指定要刪除的圖書編號;pageNO是請求參數,保持狀態的目的是爲了刪除後讓頁面繼續停留在某一頁,不過這裏有問題的是當某一頁的內容只有一條記錄裏就須要從新計算了;rediredtAttributes是爲了保持重定向後的message值。
package com.tax.controller; import com.tax.service.IBookService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.annotation.Resource; /** * 圖書控制器 */ @Controller @RequestMapping("/book") public class BookController { @Resource IBookService bookService; @RequestMapping("/list") public String list(Model model) { //得到全部的圖書帶到頁面中 model.addAttribute("books", bookService.getAllBooks()); return "book/list"; //WEB-INF/views/book/list.jsp } //http://localhost:8080/ssm/book/del/5 @RequestMapping("/del/{id}") public String del(Model model, @PathVariable int id, RedirectAttributes flash) { //執行刪除,若是影響行行數大於0,則成功 if (bookService.delete(id) > 0) { flash.addFlashAttribute("msg","刪除成功!"); } else { flash.addFlashAttribute("msg","刪除失敗!"); } //重定向 return "redirect:/book/list"; } @RequestMapping("/dels") public String dels(Model model, @RequestParam(value = "id",required = false) int[] ids, RedirectAttributes flash) { //執行刪除,若是影響行行數大於0,則成功 int rows=bookService.delete(ids); if ( rows> 0) { flash.addFlashAttribute("msg","刪除成功"+rows+"行!"); } else { flash.addFlashAttribute("msg","刪除失敗!"); } //重定向 return "redirect:/book/list"; } }
爲了配合刪除,修改list.jsp頁面,修改後的list.jsp頁面以下所示:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>圖書管理</title> <meta charset="UTF-8"/> </head> <body> <h2>圖書管理</h2> <form action="dels" method="post"> <table width="100%" id="tab" border="1"> <tr> <td><input type="checkbox" id="chbAll" /></td> <td>編號</td> <td>書名</td> <td>類型</td> <td>價格</td> <td>狀態</td> <td>操做</td> </tr> <c:forEach var="book" items="${books}"> <tr> <td><input name="id" type="checkbox" value="${book.id}"/></td> <td>${book.id}</td> <td>${book.title}</td> <td>${book.typename}</td> <td>${book.price}</td> <td>${book.state}</td> <td><a href="del/${book.id}" class="del">刪除</a> | <a href="#">編輯</a></td> </tr> </c:forEach> </table> <p> <input type="submit" value="刪除選擇項" class="del"/> </p> </form> <p> ${msg} </p> <script src="<c:url value="/js/jquery-1.11.3.min.js"></c:url>"></script> <script> $(".del").click(function(){ return confirm("您肯定要刪除嗎?"); }); //全選與反選 $("#chbAll").change(function(){ $("input[name=id]").prop("checked",$(this).prop("checked")); }); var msg='${msg}'; if(msg){ alert(msg); } </script> </body> </html>
運行結果以下所示:
基中的多刪除功能能夠改進爲一次性讓數據庫刪除完成。
11.三、新增圖書功能
在控制器中添加2個action,一個是add用於完成添加頁面展現,一個是addSave用於完成添加保存處理,代碼以下:
//添加 @RequestMapping("/add") public String add(Model model) { return "book/add"; } //添加保存 @RequestMapping("/addSave") public String add(Model model, Book book, RedirectAttributes flash) { //執行刪除,若是影響行行數大於0,則成功 if (bookService.add(book) > 0) { flash.addFlashAttribute("msg","添加成功!"); //重定向 return "redirect:/book/list"; } else { flash.addFlashAttribute("msg","添加失敗!"); flash.addFlashAttribute("",book); return "redirect:/book/add"; } }
在views/jstl/book目錄下新增長add.jsp頁面,頁面內容以下:
<%-- Created by IntelliJ IDEA. User: Administrator Date: 2018/3/20 Time: 10:31 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>添加圖書</title> <meta charset="UTF-8"/> </head> <body> <h2>添加圖書</h2> <form action="addSave" method="post"> <fieldset> <legend>圖書詳細</legend> <p> <label for="title">書名:</label> <input type="text" name="title" id="title" value="${book.title}"/> </p> <p> <label for="typename">類型:</label> <select name="typename" id="typename"> <option value="經濟">經濟</option> <option value="文學">文學</option> <option value="天文">天文</option> </select> </p> <p> <label for="price">價格:</label> <input type="text" name="price" id="price" value="${book.price}"/> </p> <p> <label for="state2">狀態:</label> <input type="radio" name="state" id="state1" value="已借出"/>已借出 <input type="radio" name="state" id="state2" value="未借出"/>未借出 </p> <p> <input type="submit" value="提交"/> </p> </fieldset> </form> </body> </html>
首頁添加新增按鈕
<p> <input type="submit" value="刪除選擇項" class="del"/> <input type="button" value="添加" onclick="location.href='<c:url value="/book/add"></c:url>'" /> </p>
運行結果:
執行添加
11.四、編輯圖書功能
與新增長相似,在控制器下新增兩個action,一個用於展現編輯,有一個用於執行編輯後保存,代碼以下所示:
//編輯 @RequestMapping("/edit") public String edit(Model model,int id) { //將要編輯的圖書對象帶入視圖 model.addAttribute("book",bookService.getBookById(id)); return "book/edit"; } //編輯保存 @RequestMapping("/editSave") public String edit(Model model, Book book, RedirectAttributes flash) { //執行更新,若是影響行行數大於0,則成功 if (bookService.edit(book) > 0) { flash.addFlashAttribute("msg","更新成功!"); //重定向 return "redirect:/book/list"; } else { flash.addFlashAttribute("msg","更新失敗!"); flash.addFlashAttribute("book",book); return "redirect:/book/edit"; } }
在views/jstl/book目錄下新增長edit.jsp頁面,頁面內容以下:
<%-- Created by IntelliJ IDEA. User: Administrator Date: 2018/3/20 Time: 10:31 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>編輯圖書</title> <meta charset="UTF-8"/> </head> <body> <h2>編輯圖書</h2> <form action="editSave" method="post"> <fieldset> <legend>圖書詳細</legend> <p> <label for="title">書名:</label> <input type="text" name="title" id="title" value="${book.title}"/> </p> <p> <label for="typename">類型:</label> <select name="typename" id="typename"> <option value="計算機" ${book.typename=="計算機"?"selected='selected'":""}>計算機</option> <option value="軟件工程" ${book.typename=="軟件工程"?"selected='selected'":""}>軟件工程</option> <option value="神話" ${book.typename=="神話"?"selected='selected'":""}>神話</option> <option value="軟件開發" ${book.typename=="軟件開發"?"selected='selected'":""}>軟件開發</option> </select> </p> <p> <label for="price">價格:</label> <input type="text" name="price" id="price" value="${book.price}"/> </p> <p> <label for="state2">狀態:</label> <input type="radio" name="state" id="state1" value="已借出" ${book.state=="已借出"?"checked='checked'":""}/>已借出 <input type="radio" name="state" id="state2" value="未借出" ${book.state=="未借出"?"checked='checked'":""}/>未借出 </p> <p> <input type="hidden" name="id" value="${book.id}" /> <input type="submit" value="保存"/> </p> </fieldset> </form> </body> </html>
首頁編輯按鈕:
<td><a href="del/${book.id}" class="del">刪除</a> | <a href="<c:url value="/book/edit?id=${book.id}"></c:url>">編輯</a></td>
運行結果:
11.五、日誌、首頁、樣式與最終的控制器
爲了將MyBatis與Hibernate Validation的日誌信息展現在控制中,須要添加log4j2的引用,這部份內容在pom.xml中已配置完成了,另外在項目的根目錄下須要添加一個log4j2的配置文件log4j2.xml,內容以下:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="off" monitorInterval="1800"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" /> </Console> </Appenders> <Loggers> <Root level="debug"> <AppenderRef ref="Console" /> </Root> </Loggers> </Configuration>
在webapp目錄下添加index.jsp,首頁是這個程序的入口,只完成了轉發功能,頁面內容以下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <jsp:forward page="Book/list"></jsp:forward>
全部頁面基本都引用了同一個樣式表styles/main.css文件,文件內容以下:
最終的控制器BookController.java文件內容以下:
package com.tax.controller; import com.tax.model.Book; import com.tax.service.IBookService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import javax.annotation.Resource; /** * 圖書控制器 */ @Controller @RequestMapping("/book") public class BookController { @Resource IBookService bookService; @RequestMapping("/list") public String list(Model model) { //得到全部的圖書帶到頁面中 model.addAttribute("books", bookService.getAllBooks()); return "book/list"; //WEB-INF/views/book/list.jsp } //單刪除 @RequestMapping("/del/{id}") public String del(Model model, @PathVariable int id, RedirectAttributes flash) { //執行刪除,若是影響行行數大於0,則成功 if (bookService.delete(id) > 0) { flash.addFlashAttribute("msg","刪除成功!"); } else { flash.addFlashAttribute("msg","刪除失敗!"); } //重定向 return "redirect:/book/list"; } //多刪除 @RequestMapping("/dels") public String dels(Model model, @RequestParam(value = "id",required = false) int[] ids, RedirectAttributes flash) { //執行刪除,若是影響行行數大於0,則成功 int rows=bookService.delete(ids); if ( rows> 0) { flash.addFlashAttribute("msg","刪除成功"+rows+"行!"); } else { flash.addFlashAttribute("msg","刪除失敗!"); } //重定向 return "redirect:/book/list"; } //添加 @RequestMapping("/add") public String add(Model model) { return "book/add"; } //添加保存 @RequestMapping("/addSave") public String add(Model model, Book book, RedirectAttributes flash) { //執行保存,若是影響行行數大於0,則成功 if (bookService.add(book) > 0) { flash.addFlashAttribute("msg","添加成功!"); //重定向 return "redirect:/book/list"; } else { flash.addFlashAttribute("msg","添加失敗!"); flash.addFlashAttribute("book",book); return "redirect:/book/add"; } } //編輯 @RequestMapping("/edit") public String edit(Model model,int id) { //將要編輯的圖書對象帶入視圖 model.addAttribute("book",bookService.getBookById(id)); return "book/edit"; } //編輯保存 @RequestMapping("/editSave") public String edit(Model model, Book book, RedirectAttributes flash) { //執行更新,若是影響行行數大於0,則成功 if (bookService.edit(book) > 0) { flash.addFlashAttribute("msg","更新成功!"); //重定向 return "redirect:/book/list"; } else { flash.addFlashAttribute("msg","更新失敗!"); flash.addFlashAttribute("book",book); return "redirect:/book/edit"; } } }
整合H-UI後的效果
12、總結與問題
通個該示例將前面幾章的內容整合起來,鞏固了前幾章的內容;示例中還能夠嘗試使用FreeMarker視圖;示例中沒有前端驗證都是後臺驗證,可使用jQuery擴展插件Validate實現前端校驗;有些功能能夠結合AJAX完成更加合理;路徑是要很是當心的,後臺重定向時,前臺提交表單的路徑,可使用base標籤和c:url。內容比較簡單,適合初學,只是但願能起到拋磚引玉、以小見大的做用,謝謝閱讀!
在Idea的spring工程裏,常常會遇到Could not autowire. No beans of 'xxxx' type found的錯誤提示。但程序的編譯和運行都是沒有問題的,這個錯誤提示並不會產生影響。
下降Autowired檢測的級別,將Severity的級別由以前的error改爲warning或其它能夠忽略的級別。