项目:我的博客系统 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层。完成主要的先后端功能。