在实战中学习,模仿博客园的部分功能。包括用户的注册,登陆;发表新随笔,阅读随笔;发表评论,以及定时任务等。Entity层设计3张表,分别为user表(用户),essay表(随笔)以及comment表(评论)。表结构如下:
项目开发采用Intellij IDEA + maven,整个项目结构如下如下图所示:
在项目的pom.xml文件中,导入项目需要的依赖。pom.xml内容如下所示:
1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 3 <modelVersion>4.0.0</modelVersion> 4 <groupId>spring_demo2</groupId> 5 <artifactId>com.everSeeker</artifactId> 6 <packaging>war</packaging> 7 <version>1.0</version> 8 <name>com.everSeeker Maven Webapp</name> 9 <url>http://maven.apache.org</url> 10 <dependencies> 11 12 <!--数据库相关, mysql, mybatis--> 13 <dependency> 14 <groupId>mysql</groupId> 15 <artifactId>mysql-connector-java</artifactId> 16 <version>5.1.38</version> 17 </dependency> 18 <dependency> 19 <groupId>org.mybatis</groupId> 20 <artifactId>mybatis</artifactId> 21 <version>3.3.0</version> 22 </dependency> 23 <dependency> 24 <groupId>org.mybatis</groupId> 25 <artifactId>mybatis-spring</artifactId> 26 <version>1.2.3</version> 27 </dependency> 28 29 <!--数据源配置, dataSource--> 30 <dependency> 31 <groupId>c3p0</groupId> 32 <artifactId>c3p0</artifactId> 33 <version>0.9.1.2</version> 34 </dependency> 35 36 <!--事务相关, transcationManager--> 37 <dependency> 38 <groupId>org.springframework</groupId> 39 <artifactId>spring-jdbc</artifactId> 40 <version>4.2.4.RELEASE</version> 41 </dependency> 42 43 <dependency> 44 <groupId>org.springframework</groupId> 45 <artifactId>spring-tx</artifactId> 46 <version>4.2.4.RELEASE</version> 47 </dependency> 48 49 <!--可以找到使用Spring ApplicationContext特性时所需的全部类,JDNI 所需的全部类,instrumentation组件以及校验Validation 方面的相关类。外部依赖spring-beans, (spring-aop)。--> 50 <!--提供基于注解的配置, 比如@Component, @Service, @Repository, @Controller等--> 51 <dependency> 52 <groupId>org.springframework</groupId> 53 <artifactId>spring-context</artifactId> 54 <version>4.2.4.RELEASE</version> 55 <!--<exclusions>--> 56 <!--<exclusion>--> 57 <!--<artifactId>commons-logging</artifactId>--> 58 <!--<groupId>commons-logging</groupId>--> 59 <!--</exclusion>--> 60 <!--</exclusions>--> 61 </dependency> 62 <dependency> 63 <groupId>org.springframework</groupId> 64 <artifactId>spring-context-support</artifactId> 65 <version>4.2.4.RELEASE</version> 66 </dependency> 67 68 <dependency> 69 <groupId>junit</groupId> 70 <artifactId>junit</artifactId> 71 <version>4.12</version> 72 <scope>test</scope> 73 </dependency> 74 <dependency> 75 <groupId>org.springframework</groupId> 76 <artifactId>spring-test</artifactId> 77 <version>4.2.4.RELEASE</version> 78 </dependency> 79 80 <!--任务调度--> 81 <dependency> 82 <groupId>org.quartz-scheduler</groupId> 83 <artifactId>quartz</artifactId> 84 <version>2.2.1</version> 85 </dependency> 86 87 <dependency> 88 <groupId>org.springframework</groupId> 89 <artifactId>spring-web</artifactId> 90 <version>4.2.4.RELEASE</version> 91 </dependency> 92 93 <!--log4j && slf4j--> 94 <dependency> 95 <groupId>org.slf4j</groupId> 96 <artifactId>slf4j-api</artifactId> 97 <version>1.7.14</version> 98 </dependency> 99 <dependency> 100 <groupId>org.slf4j</groupId> 101 <artifactId>slf4j-log4j12</artifactId> 102 <version>1.7.14</version> 103 </dependency> 104 <dependency> 105 <groupId>org.slf4j</groupId> 106 <artifactId>jcl-over-slf4j</artifactId> 107 <version>1.7.14</version> 108 <scope>runtime</scope> 109 </dependency> 110 111 </dependencies> 112 113 <build> 114 <finalName>com.everSeeker</finalName> 115 </build> 116 </project>
下面开始详细介绍。
一、Mybatis
1、先做准备工作。在mysql数据库中创建表。
1 create database if NOT EXISTS spring_demo default character set utf8; 2 use spring_demo; 3 show engines; 4 5 create table if not exists user(id int primary key not null auto_increment, username varchar(12) not null, password varchar(20), score int, ranking int, essay_count int, UNIQUE(username)) engine=InnoDB; 6 show table status like 'user'\G; 7 8 create table if not exists essay(id int primary key not null auto_increment, title varchar(40) not null, create_date datetime, user_id int, reading_count int, comment_count int, tag varchar(40), UNIQUE(title)) engine=InnoDB; 9 show table status like 'essay'\G; 10 11 create table if not exists comment(id int PRIMARY KEY NOT NULL AUTO_INCREMENT, content TEXT, user_id int, essay_id int, comment_date DATETIME) ENGINE=InnoDB; 12 show table status like 'comment'\G;
2、在entity目录下创建与数据库中表对应的类,以user表为例。
1 package com.everSeeker.entity; 2 3 import java.io.Serializable; 4 5 /** 6 * 对象的序列化 class implements Serializable 7 * 参考文档:http://www.cnblogs.com/xudong-bupt/archive/2013/05/19/3086493.html 8 */ 9 public class User implements Serializable { 10 private int id; 11 private String username; 12 private String password; 13 private int score; 14 private int ranking; 15 private int essayCount; 16 17 public User() {} 18 19 public User(String username, String password) { 20 this.username = username; 21 this.password = password; 22 score = 0; 23 ranking = 0; 24 essayCount = 0; 25 } 26 27 public int getId() { 28 return id; 29 } 30 31 public void setId(int id) { 32 this.id = id; 33 } 34 35 public String getUsername() { 36 return username; 37 } 38 39 public void setUsername(String username) { 40 this.username = username; 41 } 42 43 public String getPassword() { 44 return password; 45 } 46 47 public void setPassword(String password) { 48 this.password = password; 49 } 50 51 public int getScore() { 52 return score; 53 } 54 55 public void setScore(int score) { 56 this.score = score; 57 } 58 59 public int getRanking() { 60 return ranking; 61 } 62 63 public void setRanking(int ranking) { 64 this.ranking = ranking; 65 } 66 67 public int getEssayCount() { 68 return essayCount; 69 } 70 71 public void setEssayCount(int essayCount) { 72 this.essayCount = essayCount; 73 } 74 75 @Override 76 public String toString() { 77 return "User [id=" + id + ", username=" + username + ", password=" + password + ", score=" + score + 78 ", rankding=" + ranking + ", essayCount=" + essayCount + "]"; 79 } 80 }
3、在dao目录下创建操作数据表的接口,以userDao为例。
1 package com.everSeeker.dao; 2 3 import com.everSeeker.entity.User; 4 import org.apache.ibatis.annotations.Param; 5 import org.springframework.stereotype.Repository; 6 7 @Repository 8 public interface UserDao { 9 10 void addUser(@Param("user") User user); 11 12 User getUserById(int id); 13 14 User getUserByUsername(String username); 15 16 void updateUser(User user); 17 18 void rankingByScore(); 19 }
4、为使用mybatis管理操作数据库,首先需要设置spring与mybatis配合使用的相关配置。
mybatis.xml:在本项目中,仅仅用作给实体类配置别名。
spring-mybatis.xml:在本项目中,用来配置数据源dataSource,sqlSessionFactory等。
具体文件内容如下:
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> 4 5 <configuration> 6 7 <!--配置实体类的别名--> 8 <typeAliases> 9 <!--以下2种方法选其一即可。 第1种方法:使用typeAlias,为单个类设置别名。--> 10 <typeAlias type="com.everSeeker.entity.User" alias="User" /> 11 <typeAlias type="com.everSeeker.entity.Essay" alias="Essay" /> 12 <typeAlias type="com.everSeeker.entity.Comment" alias="Comment" /> 13 <!--第2种方法:使用package,为包下面的所有类设置别名,默认规则为com.everSeeker.entity.User设置为User,去除前面的包名。--> 14 <!--<package name="com.everSeeker.entity" />--> 15 </typeAliases> 16 17 </configuration>
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:tx="http://www.springframework.org/schema/tx" 5 xmlns:p="http://www.springframework.org/schema/p" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 8 http://www.springframework.org/schema/tx 9 http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> 10 11 <!--数据源配置 c3p0 12 常见的数据源实现类包有2个,一个是apache的DBCP(org.apache.commons.dbcp.BasicDataSource),另一个为C3P0。 13 --> 14 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" 15 destroy-method="close"> 16 17 <property name="driverClass" value="${db.mysql.driverClass}" /> 18 <property name="jdbcUrl" value="${db.mysql.jdbcUrl}" /> 19 <property name="user" value="${db.mysql.user}" /> 20 <property name="password" value="${db.mysql.password}" /> 21 22 <!--连接池中保留的最小连接数。 --> 23 <property name="minPoolSize" value="${db.minPoolSize}" /> 24 25 <!--连接池中保留的最大连接数。Default: 15 --> 26 <property name="maxPoolSize" value="${db.maxPoolSize}" /> 27 28 <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 --> 29 <property name="initialPoolSize" value="${db.initialPoolSize}" /> 30 31 <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --> 32 <property name="maxIdleTime" value="${db.maxIdleTime}" /> 33 34 <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --> 35 <property name="acquireIncrement" value="${db.acquireIncrement}" /> 36 37 <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。 38 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 --> 39 <property name="maxStatements" value="${db.maxStatements}" /> 40 41 <!--每60秒检查所有连接池中的空闲连接。Default: 0 --> 42 <property name="idleConnectionTestPeriod" value="${db.idleConnectionTestPeriod}" /> 43 44 <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 --> 45 <property name="acquireRetryAttempts" value="${db.acquireRetryAttempts}" /> 46 47 <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试 48 获取连接失败后该数据源将申明已断开并永久关闭。Default: false --> 49 <property name="breakAfterAcquireFailure" value="${db.breakAfterAcquireFailure}" /> 50 51 <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable 52 等方法来提升连接测试的性能。Default: false --> 53 <property name="testConnectionOnCheckout" value="${db.testConnectionOnCheckout}" /> 54 </bean> 55 56 <!-- myBatis配置. 57 classpath和classpath*的区别,参考文档:http://blog.csdn.net/zl3450341/article/details/9306983. 58 classpath只会返回第一个匹配的资源,建议确定路径的单个文档使用classpath;匹配多个文档时使用classpath*. 59 --> 60 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" 61 p:dataSource-ref="dataSource" 62 p:configLocation="classpath:mybatis.xml" 63 p:mapperLocations="classpath*:com/everSeeker/*Mapper.xml" /> 64 65 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 66 <!--basePackage指定要扫描的包,在此包之下的映射器都会被搜索到。可指定多个包,包与包之间用逗号或分号分隔 67 MapperScannerConfigurer将扫描basePackage所指定包下的所有接口类(包括子包),如果他们在SQL映射文件 68 中定义过,则将他们动态定义为一个Spring Bean. --> 69 <property name="basePackage" value="com.everSeeker.dao" /> 70 <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> 71 <!--<property name="annotationClass" value="com.everSeeker.dao" />--> 72 </bean> 73 74 </beans>
在spring-mybatis.xml文件中,引入了db.properties文件中的内容。
1 # Database 2 db.mysql.driverClass = com.mysql.jdbc.Driver 3 db.mysql.jdbcUrl = jdbc:mysql://localhost:3306/spring_demo?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true 4 db.mysql.user = root 5 db.mysql.password = 333 6 db.minPoolSize = 10 7 db.maxPoolSize = 100 8 db.initialPoolSize = 20 9 db.maxIdleTime = 60 10 db.acquireIncrement = 5 11 db.maxStatements = 100 12 db.idleConnectionTestPeriod = 60 13 db.acquireRetryAttempts = 30 14 db.breakAfterAcquireFailure = true 15 db.testConnectionOnCheckout = false
最后,在spring.xml配置文件中载入与mybatis相关的配置文件。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/context 8 http://www.springframework.org/schema/context/spring-context.xsd"> 9 10 <!-- 加载Spring配置文件 --> 11 <context:property-placeholder location="classpath:db.properties"/> 12 <context:property-placeholder location="classpath:log4j.properties"/> 13 14 <import resource="classpath:spring-mybatis.xml"/> 15 16 <!-- 使用spring annotation自动扫描配置 --> 17 <context:component-scan base-package="com.everSeeker"/> 18 <!-- 自动注入 --> 19 <context:annotation-config/> 20 21 </beans>
5、准备工作已经完成,现在就可以通过在**Mapper.xml文件中以直接写sql语句的方式来操作数据库并同时实现dao层中相关类的接口了。以UserDao为例,在resources/com/everSeeker目录下创建对应的UserMapper.xml文件。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 3 4 <mapper namespace="com.everSeeker.dao.UserDao"> 5 <resultMap id="ResultMapUser" type="com.everSeeker.entity.User"> 6 <id column="id" property="id"/> 7 <result column="username" property="username"/> 8 <result column="password" property="password"/> 9 <result column="score" property="score"/> 10 <result column="ranking" property="ranking"/> 11 <result column="essay_count" property="essayCount"/> 12 </resultMap> 13 14 <insert id="addUser" parameterType="User"> 15 INSERT INTO user(username, password, score, ranking, essay_count) VALUES(#{user.username}, #{user.password}, #{user.score}, #{user.ranking}, #{user.essayCount}) 16 </insert> 17 18 <select id="getUserById" parameterType="int" resultMap="ResultMapUser"> 19 SELECT * FROM user WHERE id=#{id} 20 </select> 21 22 <select id="getUserByUsername" parameterType="String" resultMap="ResultMapUser"> 23 SELECT * FROM user where username=#{username} 24 </select> 25 26 <update id="updateUser" parameterType="User"> 27 UPDATE user SET username=#{username}, password=#{password}, score=#{score}, ranking=#{ranking}, essay_count=#{essayCount} where id=#{id} 28 </update> 29 30 <!--在mysql中执行多条语句,可以采用存储过程,如{call proc()};也可以通过连接数据库时设置allowMultiQueries=true来实现--> 31 <update id="rankingByScore"> 32 -- { call proc() } 33 SET @row=0; 34 UPDATE user SET ranking=(@row:=@row+1) ORDER BY score DESC; 35 </update> 36 </mapper>
6、更多关于mybatis的内容参考:
1) http://www.mybatis.org/mybatis-3/zh/index.html
2) 如果数据表中的column字段和modal(entity)中定义的类的字段不一致,比如数据库中User表有字段t_username,而在类User中定义字段username,则可以使用ResultMap来代替ResultType。详细信息可参考MyBatis中关于resultType和resultMap的区别以及MyBatis魔法堂:ResultMap详解以及MyBatis魔法堂:即学即用篇。