項目:我的博客系統 Part2前端
搭建Spring + SpringMVC + MyBatis框架java
整合Spring與MyBatis;mysql
首先pom注入相應的jar包:git
<properties> <spring.version>4.1.1.RELEASE</spring.version> </properties> <dependencies> <!-- spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!--Velocity須要的jar包--> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-tools</artifactId> <version>2.0</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!--數據庫鏈接池--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.15</version> </dependency> <!--MyBatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.2.3</version> </dependency> <!--log--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.7</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.7</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.1</version> </dependency> <!-- JSTL --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> </dependencies>
而後配置spring-mybatis.xml文件:github
<context:annotation-config/> <context:component-scan base-package="com.leng.blogTMY"/>
<!--導入數據鏈接池配置文件--> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties"/> <property name="fileEncoding" value="utf-8"/> </bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClassName}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> <!-- 初始化鏈接大小 --> <property name="initialSize" value="${initialSize}"/> <!-- 鏈接池最大數量 --> <property name="maxActive" value="${maxActive}"/> <!-- 鏈接池最大空閒 --> <property name="maxIdle" value="${maxIdle}"/> <!-- 鏈接池最小空閒 --> <property name="minIdle" value="${minIdle}"/> <!-- 獲取鏈接最大等待時間 --> <property name="maxWait" value="${maxWait}"/> </bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!--<property name="mapperLocations" value="classpdaopper/*.xml"/>--> <property name="mapperLocations" value="classpath:mapper/*.xml" /> <property name="typeAliasesPackage" value="com.leng.blogTMY.model"/> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageHelper"> <property name="properties"> <value> reasonable=true </value> </property> </bean> </array> </property> </bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.leng.blogTMY.dao"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean>
完整的spring-mybatis文件:web
<?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:tx="http://www.springframework.org/schema/tx" 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.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <context:annotation-config/> <context:component-scan base-package="com.leng.blogTMY"/> <!--導入數據鏈接池配置文件--> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties"/> <property name="fileEncoding" value="utf-8"/> </bean> <!--數據鏈接池配置--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${driverClassName}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> <!-- 初始化鏈接大小 --> <property name="initialSize" value="${initialSize}"/> <!-- 鏈接池最大數量 --> <property name="maxActive" value="${maxActive}"/> <!-- 鏈接池最大空閒 --> <property name="maxIdle" value="${maxIdle}"/> <!-- 鏈接池最小空閒 --> <property name="minIdle" value="${minIdle}"/> <!-- 獲取鏈接最大等待時間 --> <property name="maxWait" value="${maxWait}"/> </bean> <!--Spring Mybatis整合--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!--<property name="mapperLocations" value="classpdaopper/*.xml"/>--> <property name="mapperLocations" value="classpath:mapper/*.xml" /> <property name="typeAliasesPackage" value="com.leng.blogTMY.model"/> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageHelper"> <property name="properties"> <value> reasonable=true </value> </property> </bean> </array> </property> </bean> <!-- DAO接口所在包名,Spring會自動查找其下的類 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.leng.blogTMY.dao"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean> <!-- (事務管理)transaction manager, use JtaTransactionManager for global tx --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> </beans>
jdbc.properties:spring
driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/blogTMY?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull username=root password=xxxxx initialSize=0 maxActive=20 maxIdle=20 minIdle=1 maxWait=60000
注意,url後面必定要加上編碼設置utf-8,不然存入數據庫的數據會出現亂碼狀況!!sql
url=jdbc:mysql://localhost:3306/blogTMY?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
以上爲Spring與MyBatis的整合。數據庫
<context:component-scan base-package="com.leng.blogTMY"/> <mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="order" value="1"/> <property name="viewClass" value="com.leng.blogTMY.util.JspResourceView"/> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp"/> </bean>
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/manage"/> <mvc:mapping path="/manage/*"/> <mvc:mapping path="/manage/**"/> <bean class="com.leng.blogTMY.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>
以上爲SpringMVC配置內容。apache
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mybatis.xml</param-value> </context-param>
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
<servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
<filter> <filter-name>encodingFilter</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>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
以上爲web.xml的主要配置。
至此,Spring+SpringMVC+MyBatis框架搭建完成。
能夠寫一個簡單的mvc工做流程測試框架。
blog基本功能包括文章的增刪改查,用戶的信息,文章的分類等。
因此簡單肯定model層能夠包括:User、Article、Category;
user和article是一對多的關係;
article和category是多對一的關係;
爲何須要dto包?
數據傳輸對象DTO自己並非業務對象。數據傳輸對象是根據UI的需求進行設計的,而不 是根據領域對象進行設計的。好比,Customer領域對象可能會包含一些諸如FirstName, LastName, Email, Address等信息。但若是UI上不打算顯示Address的信息,那麼CustomerDTO中也無需包含這個 Address的數據
簡單來講Model面向業務,咱們是經過業務來定義Model的。而DTO是面向界面UI,是經過UI的需求來定義的。經過DTO咱們實現了表現層與Model之間的解耦,表現層不引用Model,若是開發過程當中咱們的模型改變了,而界面沒變,咱們就只須要改Model而不須要去改表現層中的東西。
/** * Created by leng on 2017/7/2. * id 文章id * title 文章標題 * content 文章內容 * putDate 文章發佈日期 * clicks 點擊次數 * remark 評論 * picture 圖片 * isDraft 是否草稿 默認0 * category 分類 * user 用戶 */ public class ArticleDto { private Integer id; private String title; private String content; private String markDown; private String pubDate; private Integer clicks; private String remark; private String picture; private Integer isDraft; private Category category; private UserDto user; //getter, setter, tostring... }
package com.leng.blogTMY.model.dto; /** * Created by leng on 2017/7/2. * ArticleLiteDto 是用來在 首頁 中顯示文章的基本狀況的。好比 標題 發佈日期 有些blog 還會顯示內容簡介. * 能夠減小對數據庫的讀取訪問量.在首頁中顯示不須要顯示文章的內容和markdown內容. */ public class ArticleLiteDto { private Integer id; private String title; private String pubDate; private Integer clicks; private String remark; private UserDto user; //getter, setter... @Override public String toString() { return "ArticleLiteDto{" + "id=" + id + ", title='" + title + '\'' + ", pubDate='" + pubDate + '\'' + ", clicks=" + clicks + ", remark='" + remark + '\'' + ", user=" + user + '}'; } }
/** * Created by leng on 2017/7/2. */ @Repository public interface ArticleDao { //搜索文章根據文章標題 List<ArticleDto> search(Article a_title) throws Exception; //分頁 List<ArticleDto> pagerAction(Pager pager) throws Exception; //獲取文章Dto ArticleDto getArticleDto(Integer id) throws Exception; //獲取上一篇文章 ArticleLiteDto getPreArticleDto(Integer id) throws Exception; //獲取下一篇文章 ArticleLiteDto getNextArticleDto(Integer id) throws Exception; //獲取某分類下文章 List<ArticleLiteDto> getByCategory(int categoryId) throws Exception; //歸檔 List<ArticleLiteDto> archive() throws Exception; //更新點擊 void updateArticleClicks(Integer clicks, Integer id) throws Exception; //更新文章 void update(Article article) throws Exception; //保存文章 void save(Article article) throws Exception; //刪除文章 void delete(Integer id) throws Exception; //數量統計 int count() throws Exception; }
編寫xml配置文件實現dao接口的方法;
注意mapper文件夾下的xml文件要放在resource包下,不然有可能不被掃描的。
或者在pom的<build>裏添加以下配置:
<resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/resources</directory> </resource> </resources>
mapper的xml文件編寫的幾點注意點:
1.namespace要和對應dao接口包名稱一致;
2.方法名要和id一致;
不然會出現Invalid bound statement (not found) Mybatis綁定失敗
UserMapper和ArticleMapper都比較常規;須要注意的是resultMap的要注意column和property的值不能寫錯,column對應數據庫,property對應model;
比較特殊的是獲取Category下的categoryCount須要用到RIGHT JOIN
<select id="all" resultMap="categoryDto"> SELECT t_category.categoryId, t_category.categoryName, COUNT(articleId) AS categoryCount FROM t_article RIGHT JOIN t_category ON t_article.categoryId = t_category.categoryId GROUP BY t_category.categoryId </select>
與Dao接口方法相似;
其中分頁方法須要編寫分頁工具類Pager:
屬性包括:pageSize、currentPage、totalRecord、totalPage;以及firstPage、lastPage、prePage、nextPage;
package com.leng.blogTMY.util; /** * Created by leng on 2017/7/2. */ public class Pager { private int pageSize;//每頁顯示數據條數 private int currentPage;//當前頁面 private int totalRecord;//總數據條數 private int totalPage;//總頁面數 public int getTotalPage() { return totalPage; } //首頁 private int firstPage; //末頁 private int lastPage; //上一頁 private int prePage; //下一頁 private int nextPage; public Pager() { } public Pager(int currentPage, int pageSize, int totalRecord) { this.pageSize = pageSize; this.totalRecord = totalRecord; this.totalPage = calculateTotalPage(); //負責計算 傳入的 頁面索引 是否超出最大頁面數值 超出就設置爲最大頁面索引 this.currentPage = currentPage > totalPage ? totalPage : currentPage; } private int calculateTotalPage() { this.totalPage = this.totalRecord / this.pageSize; if (totalRecord % pageSize != 0) { this.totalPage = this.totalPage + 1; } return totalPage; } // getter, setter... public int getFirstPage() { this.firstPage = 1; return this.firstPage; } public int getLastPage() { this.lastPage = totalPage; return lastPage; } public int getPrePage() { if (this.currentPage <= 1) { this.prePage = firstPage; }else { this.prePage = this.currentPage - 1; } return this.prePage; } public int getNextPage(){ if(this.currentPage >= totalPage){ this.nextPage = totalPage; }else { this.nextPage = this.currentPage + 1; } return this.nextPage; } public int getStartIndex(){ return (currentPage-1)*pageSize; } }
以上完成了業務邏輯的編寫。經過JUnit4寫測試類來測試service各方法。
下一部分會開始編寫controller層。完成主要的先後端功能。