一个更为详细的MyBatis(3.2.3)示例

1. 数据库中有如下三张表:

CREATE TABLE students
(
	stud_no INTEGER NOT NULL AUTO_INCREMENT,
	stud_name VARCHAR(50) NOT NULL,
	birthday DATE NOT NULL,
	email VARCHAR(128),
	PRIMARY KEY (stud_no)
) ;
CREATE TABLE teachers
(
	tch_id INTEGER NOT NULL,
	tch_name VARCHAR(50) NOT NULL,
	birthday DATE,
	tel VARCHAR(20),
	PRIMARY KEY (tch_id)
) ;
CREATE TABLE courses
(
	crs_id INTEGER NOT NULL AUTO_INCREMENT,
	crs_name VARCHAR(50) NOT NULL,
	description VARCHAR(100),
	crs_year YEAR,
	crs_season VARCHAR(10),
	tch_id INTEGER,
	PRIMARY KEY (crs_id),
	KEY (tch_id)
) ;

ALTER TABLE courses ADD CONSTRAINT FK_courses_teachers 
	FOREIGN KEY (tch_id) REFERENCES teachers (tch_id);


2. 实体类:

学生实体:

package com.huey.mybatis.entity;

import java.util.Date;

/**
 * 学生实体
 * @author huey2672
 * @version 1.0
 * @created 2014-7-25
 */
public class Student {

	private Integer no;
	private String name;
	private Date birthday;
	private String email;
	
	public Integer getNo() {
		return no;
	}
	
	public void setNo(Integer no) {
		this.no = no;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public Date getBirthday() {
		return birthday;
	}
	
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	
	public String getEmail() {
		return email;
	}
	
	public void setEmail(String email) {
		this.email = email;
	}
	
	public Student() {
		super();
	}

	public Student(Integer no, String name, Date birthday, String email) {
		super();
		this.no = no;
		this.name = name;
		this.birthday = birthday;
		this.email = email;
	}

	@Override
	public String toString() {
		return "Student [no=" + no + ", name=" + name + ", birthday="
				+ birthday + ", email=" + email + "]";
	}
	
}
教师实体:

package com.huey.mybatis.entity;

import java.util.Date;
import java.util.List;

/**
 * 教师实体
 * @author huey2672
 * @version 1.0
 * @created 2014-7-26
 */
public class Teacher {

	private Integer id;
	private String name;
	private Date birthday;
	private Tel tel;
	private List<Course> courses;
	
	public Integer getId() {
		return id;
	}
	
	public void setId(Integer id) {
		this.id = id;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public Date getBirthday() {
		return birthday;
	}
	
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	
	public Tel getTel() {
		return tel;
	}
	
	public void setTel(Tel tel) {
		this.tel = tel;
	}
	
	public List<Course> getCourses() {
		return courses;
	}
	
	public void setCourses(List<Course> courses) {
		this.courses = courses;
	}
	
	public Teacher() {
		super();
	}

	public Teacher(Integer id, String name, Date birthday, Tel tel) {
		super();
		this.id = id;
		this.name = name;
		this.birthday = birthday;
		this.tel = tel;
	}

	@Override
	public String toString() {
		return "Teacher [id=" + id + ", name=" + name + ", birthday="
				+ birthday + ", tel=" + tel + "]";
	}
	
}
教师实体的Tel属性:

package com.huey.mybatis.entity;

/**
 * 电话号码,由区号和号码组成
 * @author huey2672
 * @version 1.0
 * @created 2014-7-26
 */
public class Tel {

	private String cityCode;
	private String number;
	
	public String getCityCode() {
		return cityCode;
	}
	
	public void setCityCode(String cityCode) {
		this.cityCode = cityCode;
	}
	
	public String getNumber() {
		return number;
	}
	
	public void setNumber(String number) {
		this.number = number;
	}
	
	public Tel() {
		super();
	}

	public Tel(String cityCode, String number) {
		super();
		this.cityCode = cityCode;
		this.number = number;
	}
	
	/**
	 * 用完整的电话号码字符串构造
	 * @param fullNumber
	 */
	public Tel(String fullNumber) {
		if (fullNumber != null) {
			String[] parts = fullNumber.split("-");
			if (parts.length > 0) {
				cityCode = parts[0];
			}
			if (parts.length > 1) {
				number = parts[1];
			}
		}
	}
	
	public String getFullNumber() {
		return cityCode + "-" + number;		
	}
	
	@Override
	public String toString() {
		return getFullNumber();
	}
	
}
课程实体:

package com.huey.mybatis.entity;

/**
 * 课程实体
 * @author huey2672
 * @version 1.0
 * @created 2014-7-28
 */
public class Course {

	private Integer id;
	private String name;
	private String description;
	private int year;
	private Season season;
	private Teacher teacher;
	
	public Integer getId() {
		return id;
	}
	
	public void setId(Integer id) {
		this.id = id;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getDescription() {
		return description;
	}
	
	public void setDescription(String description) {
		this.description = description;
	}
	
	public int getYear() {
		return year;
	}
	
	public void setYear(int year) {
		this.year = year;
	}
	
	public Season getSeason() {
		return season;
	}
	
	public void setSeason(Season season) {
		this.season = season;
	}
	
	public Teacher getTeacher() {
		return teacher;
	}
	
	public void setTeacher(Teacher teacher) {
		this.teacher = teacher;
	}
	
	public Course() {
		super();
	}

	public Course(Integer id, String name, String description, int year,
			Season season, Teacher teacher) {
		super();
		this.id = id;
		this.name = name;
		this.description = description;
		this.year = year;
		this.season = season;
		this.teacher = teacher;
	}

	@Override
	public String toString() {
		return "Course [id=" + id + ", name=" + name + ", description="
				+ description + ", year=" + year + ", season=" + season
				+ (teacher != null ? ", teacher=" + teacher.getName() : "") + "]";
	}

}
课程实体的季度属性是枚举类型:

package com.huey.mybatis.entity;

/**
 * 季度枚举
 * @author huey2672
 * @version 1.0
 * @created 2014-7-28
 */
public enum Season {
	SPRING, 
	SUMMER, 
	AUTUMN, 
	WINTER;
}


3. 在数据表teachers中tel字段是varcha类型,在实体Teacher中tel属性是自定义的JavaBean,需要自定义类型处理器处理:

package com.huey.mybatis.typehandlers;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import com.huey.mybatis.entity.Tel;

/**
 * 类型处理器TelTypeHandlers,继承BaseTypeHandler<T>
 * 当mybatis进行JDBC操作时,将自定义类型Tel转换成数据库中相应的列属性
 * 当从SQL结果集构建 JavaBean时,也有类似的过程
 * @author huey2672
 * @version 1.0
 * @created 2014-7-26
 */
public class TelTypeHandler extends BaseTypeHandler<Tel> {

	@Override
	public Tel getNullableResult(ResultSet rs, String columnName)
			throws SQLException {
		// 使用rs.getString是tel字段是VARCHER类型
		return new Tel(rs.getString(columnName));
	}

	@Override
	public Tel getNullableResult(ResultSet rs, int columnIndex)
			throws SQLException {
		return new Tel(rs.getString(columnIndex));
	}

	@Override
	public Tel getNullableResult(CallableStatement cs, int columnIndex)
			throws SQLException {
		return new Tel(cs.getString(columnIndex));
	}

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i,
			Tel param, JdbcType jdbcType) throws SQLException {
		ps.setString(i, param.getFullNumber());
	}

}

4. 映射器:

StudentMapper:

package com.huey.mybatis.mapper;

import java.util.List;

import org.apache.ibatis.session.RowBounds;

import com.huey.mybatis.entity.Student;

/**
 * 映射器StudentMapper
 * 定义了对学生实体的一些基本操作
 * @author huey2672
 * @version 1.0
 * @created 2014-7-25
 */
public interface StudentMapper {
	
	/**
	 * 添加学生记录
	 * @param student
	 * @return 数据库中受影响的行数
	 */
	public int addStudent(Student student);
	
	/**
	 * 删除学生记录
	 * @param studNo
	 * @return 数据库中受影响的行数
	 */
	public int deleteStudent(Integer studNo);
	
	/**
	 * 更新学生记录
	 * @param student
	 * @return 数据库中受影响的行数
	 */
	public int updateStudent(Student student);

	/**
	 * 根据学生学号查询学生记录
	 * @param studNo
	 * @return
	 */
	public Student getStudent(Integer studNo);
	
	/**
	 * 查询所有学生记录
	 * @return
	 */
	public List<Student> getAllStudents();
	
	/**
	 * 分页查询学生记录
	 * @param rowBounds
	 * @return
	 */
	public List<Student> getAllStudents(RowBounds rowBounds);
}
TeacherMapper:

package com.huey.mybatis.mapper;

import java.util.List;

import com.huey.mybatis.entity.Teacher;

/**
 * 映射器TeacherMapper
 * 定义了对教师实体的一些基本操作
 * @author huey2672
 * @version 1.0
 * @created 2014-7-26
 */
public interface TeacherMapper {

	/**
	 * 添加教师记录
	 * @param teacher
	 * @return 数据库中受影响的行数
	 */
	public int addTeacher(Teacher teacher);
	
	/**
	 * 删除教师记录
	 * @param tchId
	 * @return 数据库中受影响的行数
	 */
	public int deleteTeacher(Integer tchId);
	
	/**
	 * 更新教师记录
	 * @param teacher
	 * @return 数据库中受影响的行数
	 */
	public int updateTeacher(Teacher teacher);
	
	/**
	 * 根据教师编号查询教师记录
	 * @param tchId
	 * @return
	 */
	public Teacher getTeacher(Integer tchId);
	
	/**
	 * 根据教师编号查询教师记录,记录包含该教师的授课信息
	 * @param tchId
	 * @return
	 */
	public Teacher getTeacherWithCourses(Integer tchId);
	
	/**
	 * 查询所有的教师记录
	 * @return
	 */
	public List<Teacher> getAllTeachers();

}
CourseMapper:

package com.huey.mybatis.mapper;

import java.util.List;
import java.util.Map;

import com.huey.mybatis.entity.Course;
import com.huey.mybatis.entity.Season;

/**
 * 映射器CourseMapper
 * 定义了对课程实体的一些基本操作
 * @author huey2672
 * @version 1.0
 * @created 2014-7-28
 */
public interface CourseMapper {

	/**
	 * 添加课程记录
	 * @param course
	 * @return 数据库中受影响的行数
	 */
	public int addCourse(Course course);
	
	/**
	 * 删除课程记录
	 * @param crsId 要删除课程记录的ID
	 * @return 数据库中受影响的行数
	 */
	public int deleteCourse(Integer crsId);
	
	/**
	 * 更新课程记录
	 * @param course
	 * @return 数据库中受影响的行数
	 */
	public int updateCourse(Course course);
	
	/**
	 * 根据课程编号查询课程记录
	 * @param crsId
	 * @return
	 */
	public Course getCourse(Integer crsId);
	
	/**
	 * 查询所有课程记录
	 * @return
	 */
	public List<Course> getAllCourses();
	
	/**
	 * 根据授课教师编号查询课程记录
	 * @return
	 */
	public List<Course> queryCoursesByTchId(Integer tchId);
	
	/**
	 * 根据开课年度和季度查询课程记录
	 * @param year
	 * @param season
	 * @return
	 */
	public List<Course> queryCoursesByYearAndSeason(int year, Season season);
	
	/**
	 * 多条件查询课程记录
	 * @param params
	 * @return
	 */
	public List<Course> queryCourses(Map<String, Object> params);
	
}

5. 映射器SQLMapper配置文件:

StudentMapper.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">

<!--注意:此处的命名空间是StudentMapper的全限定类名-->
<mapper namespace="com.huey.mybatis.mapper.StudentMapper">

	<!-- cache元素添加全局二级缓存 -->
	<!-- 
		eviction定义缓存的移除机制,默认值是LRU(Least Recently Used)
		可选值还有FIFO(First In First Out)、SOFT(soft reference)、WEAK(weak reference)
	-->
	<!-- 
		flushInterval定义缓存刷新间隔,以毫秒计。
		默认情况下不设置。所以不使用刷新间隔,缓存cache只有调用语句的时候刷新。
	-->
	<!-- size定义缓存cache中能容纳的最大元素数。默认值是 1024,可以设置成任意的正整数。 -->
	<!-- 
		readOnly定义使用只读缓存还是读/写缓存。默认情况下设置为 false,即使用读/写缓存。
		 一个只读缓存 ache会对所有的调用者返回被缓存对象的同一个实例(实际返回的是被返回对象的一份引用)。
		 一个读/写缓存cache将会返回被返回对象的一分拷贝(通过序列化)。
	-->
	<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
	
	<!-- ResultMaps被用来将 SQL SELECT语句的结果集映射到JavaBeans的属性中 -->
	<resultMap type="Student" id="studentMap">
		<!-- 映射主键 -->
		<id property="no" column="stud_no" />
		<!-- 映射普通字段 -->
		<result property="name" column="stud_name"/>
		<result property="birthday" column="birthday"/>
		<result property="email" column="email"/>
	</resultMap>

	<!-- 添加学生记录 -->
	<!-- id名称需要与StudentMapper中的方法签名一致 -->
	<!-- Student这一别名在mybatis-config.xml中配置 -->
	<insert id="addStudent" parameterType="Student">
		insert into students(stud_no, stud_name, birthday, email)
		values(#{no}, #{name}, #{birthday}, #{email})
	</insert>

	<!-- 删除学生记录 -->
	<delete id="deleteStudent" parameterType="int">
		delete from students where stud_no=#{studNo}
	</delete>

	<!-- 更新学生记录 -->
	<update id="updateStudent" parameterType="Student">
		update students
		set stud_name=#{name}, birthday=#{birthday}, email=#{email}
		where stud_no=#{no}
	</update>

	<!-- 根据学生学号查询学生记录 -->
	<!-- 
		MyBatis自动对JavaBean中和列名匹配的属性进行填充。
		如果使用resultType="Student",那么no和name属性无法被填充,
		这是因为JavaBean中的属性名与数据库中的列名不匹配。
		也可以选择在select语句中为列名去与JavaBean属性名一致的别名。
	-->
	<select id="getStudent" parameterType="int" resultMap="studentMap" >
		select * from students where stud_no=#{studNo}
	</select>

	<!-- 查询所有学生记录 -->
	<select id="getAllStudents" resultMap="studentMap">
		select * from students
	</select>

</mapper>
TeacherMapper.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">

<!--注意:此处的命名空间是TeacherMapper的全限定类名-->
<mapper namespace="com.huey.mybatis.mapper.TeacherMapper">

	<resultMap type="Course" id="courseMap">
		<id property="id" column="crs_id" />
		<result property="name" column="crs_name"/>
		<result property="description" column="description"/>
		<result property="year" column="crs_year" />
		<result property="season" column="crs_season" />
	</resultMap>

	<!-- ResultMaps被用来将 SQL SELECT语句的结果集映射到JavaBeans的属性中 -->
	<resultMap type="Teacher" id="teacherMap">
		<!-- 映射主键 -->
		<id property="id" column="tch_id" />
		<!-- 映射普通字段 -->
		<result property="name" column="tch_name"/>
		<result property="birthday" column="birthday"/>
		<result property="tel" column="tel"/>
		<!-- collection引用了同在一个xml文件中的courseMap,导入了one-to-many类型的关联 -->
		<collection property="courses" resultMap="courseMap" />
	</resultMap>

	<!-- 添加教师记录 -->
	<!-- id名称需要与TeacherMapper中的方法签名一致 -->
	<!-- Student这一别名在mybatis-config.xml中配置 -->
	<insert id="addTeacher" parameterType="Teacher">
		insert into teachers(tch_id, tch_name, birthday, tel)
		values(#{id}, #{name}, #{birthday}, #{tel})
	</insert>

	<!-- 删除教师记录 -->
	<delete id="deleteTeacher" parameterType="int">
		delete from teachers where tch_id=#{tchId}
	</delete>

	<!-- 更新教师记录 -->
	<update id="updateTeacher" parameterType="Teacher">
		update teachers
		set tch_name=#{name}, birthday=#{birthday}, tel=#{tel}
		where tch_id=#{id}
	</update>

	<!-- 根据教师编号查询教师记录 -->
	<select id="getTeacher" parameterType="int" resultMap="teacherMap">
		select * from teachers where tch_id=#{id}
	</select>
	
	<!-- 根据教师编号查询教师记录,记录包含该教师的授课信息 -->
	<select id="getTeacherWithCourses" parameterType="int" resultMap="teacherMap">
		select t.tch_id, tch_name, birthday, tel, crs_id, crs_name, description, crs_year, crs_season
		from teachers t, courses c
		where t.tch_id = c.tch_id
		and t.tch_id = #{id}
	</select>

	<!-- 查询所有教师记录 -->
	<select id="getAllTeachers" resultMap="teacherMap">
		select * from teachers
	</select>

</mapper>
CourseMapper.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="com.huey.mybatis.mapper.CourseMapper">

	<resultMap type="Teacher" id="teacherMap">
		<id property="id" column="tch_id" />
		<result property="name" column="tch_name"/>
		<result property="birthday" column="birthday"/>
		<result property="tel" column="tel"/>
	</resultMap>

	<resultMap type="Course" id="courseMap">
		<id property="id" column="crs_id" />
		<result property="name" column="crs_name"/>
		<result property="description" column="description"/>
		<result property="year" column="crs_year" />
		<!-- 
			默认情况下, MyBatis使用 EnumTypeHandler来处理enum类型的Java属性,并且将其存储为enum值的名称。
			不需要为此做任何额外的配置。
		-->
		<result property="season" column="crs_season" />
		<!-- association引用了同在一个xml文件中的teacherMap,导入了has-one类型的关联 -->
		<association property="teacher" resultMap="teacherMap" />
	</resultMap>
	
	<!-- 定义可重用的 SQL代码段,可以包含在其他语句中 -->
	<sql id="courseColumnsWithTeacher">
		crs_id, crs_name, description, crs_year, crs_season, t.tch_id, tch_name, birthday, tel 
	</sql>

	<!-- 添加课程记录 -->
	<insert id="addCourse" parameterType="Course">
		insert into courses(crs_id, crs_name, description, crs_year, crs_season, tch_id)
		values(#{id}, #{name}, #{description}, #{year}, #{season}, #{teacher.id})
	</insert>
	
	<!-- 删除课程记录 -->
	<delete id="deleteCourse" parameterType="int">
		delete from courses where crs_id=#{crsId} 
	</delete>
	
	<!-- 更新课程记录 -->
	<update id="updateCourse" parameterType="Course">
		update courses
		set crs_name=#{name}, description=#{description}, tch_id=#{teacher.id}
		where crs_id=#{id}
	</update>

	<!-- 根据课程编号查询课程记录 -->
	<select id="getCourse" parameterType="int" resultMap="courseMap" >
		<!-- 引用sql代码段 -->
		select <include refid="courseColumnsWithTeacher"/>
		from courses c, teachers t 
		where c.tch_id = t.tch_id 
		and crs_id=#{crsId}
	</select>

	<!-- 查询所有课程记录 -->
	<select id="getAllCourses" resultMap="courseMap">
		select <include refid="courseColumnsWithTeacher"/>
		from courses c, teachers t 
		where c.tch_id = t.tch_id
	</select>
	
	<!-- 根据授课教师编号查询课程记录 -->
	<select id="queryCoursesByTchId" parameterType="int" resultMap="courseMap">
		select crs_id, crs_name, description, crs_year, crs_season, t.tch_id, tch_name, birthday, tel
		from courses c, teachers t 
		where c.tch_id = t.tch_id
		and t.tch_id = #{tchId}
	</select>

	<!-- 根据开课年度和季度查询课程记录 -->
	<!-- MyBatis支持将多个输入参数传递给映射语句,并以#{param}的语法形式引用它们 -->
	<select id="queryCoursesByYearAndSeason" resultMap="courseMap">
		select <include refid="courseColumnsWithTeacher"/>
		from courses c, teachers t 
		where c.tch_id = t.tch_id
		and crs_year = #{param1}
		and crs_season = #{param2}
	</select>
	
	<!-- 多条件查询课程记录 -->
	<!-- 动态SQL -->
	<select id="queryCourses" parameterType="map" resultMap="courseMap">
		select <include refid="courseColumnsWithTeacher"/>
		from courses c, teachers t 
		where c.tch_id = t.tch_id
		<if test="crsName!=null">
			and crs_name like #{crsName}
		</if>
		<if test="year!=null">
			and crs_year = #{year}
		</if>
		<if test="season!=null">
			and crs_season = #{season}
		</if>
	</select>

</mapper>

6. 数据库连接属性配置jdbc.properties:

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root

7.  配置文件mybatis-config.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元素可以将配置值具体化到一个属性文件中,并且使用属性文件的key名作为占位符 -->
	<properties resource="jdbc.properties">
	</properties>

	<!-- 设置别名 -->
	<typeAliases>
		<typeAlias type="com.huey.mybatis.entity.Student" alias="Student" />
		<typeAlias type="com.huey.mybatis.entity.Teacher" alias="Teacher" />
		<typeAlias type="com.huey.mybatis.entity.Course" alias="Course" />
	</typeAliases>
	
	<!-- 注册自定义类型处理器 -->
	<typeHandlers>
		<typeHandler handler="com.huey.mybatis.typehandlers.TelTypeHandler" />
	</typeHandlers>

	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<!-- 配置数据源 -->
			<dataSource type="POOLED">
				<property name="driver" value="${jdbc.driverClassName}" />
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.username}" />
				<property name="password" value="${jdbc.password}" />
			</dataSource>
		</environment>
	</environments>

	<!-- mapper对应的xml配置文件 -->
	<mappers>
		<mapper resource="com/huey/mybatis/mapper/StudentMapper.xml" />
		<mapper resource="com/huey/mybatis/mapper/TeacherMapper.xml" />
		<mapper resource="com/huey/mybatis/mapper/CourseMapper.xml" />
	</mappers>
	
</configuration>

8. 工具类MyBatisUtil:

package com.huey.mybatis.utils;

import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

/**
 * Mybatis工具类,主要负责创建、获取SqlSessionFactory实例
 * @author huey2672
 * @version 1.0
 * @created 2014-7-25
 */
public class MybatisUtil {

	private static SqlSessionFactory sessionFactory;
	private static InputStream inputStream;

	/**
	 * 加载mybatis-config.xml,创建SqlSessionFactory实例
	 */
	static {
		try {
			inputStream = Resources.getResourceAsStream("mybatis-config.xml");
			sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 每个数据库环境应该就只有一个SqlSessionFactory对象实例
	 * 所以使用单例模式只创建一个SqlSessionFactory实例
	 * @return
	 */
	public static SqlSessionFactory getSqlSessionFactory() {
		return sessionFactory;
	}

}

9. 业务逻辑层接口:

StudentServ:

package com.huey.mybatis.serv;

import java.util.List;

import com.huey.mybatis.entity.Student;

/**
 * 业务逻辑层接口StudentServ
 * @author huey2672
 * @version 1.0
 * @created 2014-7-25
 */
public interface StudentServ {

	/**
	 * 添加学生记录
	 * @param student
	 * @return 实际添加学生记录的数量
	 */
	public int addStudent(Student student);
	
	/**
	 * 删除学生记录
	 * @param studNo
	 * @return 实际删除学生记录的数量
	 */
	public int deleteStudent(Integer studNo);
	
	/**
	 * 更新学生记录
	 * @param student
	 * @return 实际更新学生记录的数量
	 */
	public int updateStudent(Student student);

	/**
	 * 根据学生学号查询学生记录
	 * @param studNo
	 * @return
	 */
	public Student getStudent(Integer studNo);
	
	/**
	 * 查询所有学生记录
	 * @return
	 */
	public List<Student> getAllStudents();
	
	/**
	 * 分页查询学生记录
	 * @param pageIndex	页码,第一页的页码为1
	 * @param pageSize	每页记录数
	 * @return
	 */
	public List<Student> pagingQueryStudents(int pageIndex, int pageSize);
	
}
TeacherServ:
package com.huey.mybatis.serv;

import java.util.List;

import com.huey.mybatis.entity.Teacher;

/**
 * 业务逻辑层接口TeacherServ
 * @author huey2672
 * @version 1.0
 * @created 2014-7-26
 */
public interface TeacherServ {

	/**
	 * 添加教师记录
	 * @param teacher
	 * @return 实际添加教师记录的数量
	 */
	public int addTeacher(Teacher teacher);
	
	/**
	 * 删除教师记录
	 * @param tchId
	 * @return 实际删除教师记录的数量
	 */
	public int deleteTeacher(Integer tchId);
	
	/**
	 * 更新教师记录
	 * @param teacher
	 * @return 实际更新教师记录的数量
	 */
	public int updateTeacher(Teacher teacher);
	
	/**
	 * 根据教师编号查询教师记录
	 * @param tchId
	 * @return
	 */
	public Teacher getTeacher(Integer tchId);
	
	/**
	 * 根据教师编号查询教师记录,记录包含该教师的授课信息
	 * @param tchId
	 * @return
	 */
	public Teacher getTeacherWithCourses(Integer tchId);
	
	/**
	 * 查询所有的教师记录
	 * @return
	 */
	public List<Teacher> getAllTeachers();
	
}
CourseServ:

package com.huey.mybatis.serv;

import java.util.List;

import com.huey.mybatis.entity.Course;
import com.huey.mybatis.entity.Season;

/**
 * 业务逻辑层接口CourseServ
 * @author huey2672
 * @version 1.0
 * @created 2014-7-28
 */
public interface CourseServ {

	/**
	 * 添加课程记录
	 * @param course
	 * @return 数据库中受影响的行数
	 */
	public int addCourse(Course course);
	
	/**
	 * 删除课程记录
	 * @param crsId 要删除课程记录的ID
	 * @return 数据库中受影响的行数
	 */
	public int deleteCourse(Integer crsId);
	
	/**
	 * 更新课程记录
	 * @param course
	 * @return 数据库中受影响的行数
	 */
	public int updateCourse(Course course);
	
	/**
	 * 根据课程ID查询课程记录
	 * @param crsId
	 * @return
	 */
	public Course getCourse(Integer crsId);
	
	/**
	 * 查询所有课程记录
	 * @return
	 */
	public List<Course> getAllCourses();
	
	/**
	 * 根据授课教师编号查询课程记录
	 * @return
	 */
	public List<Course> queryCoursesByTchId(Integer tchId);
	
	/**
	 * 根据开课年度和季度查询课程记录
	 * @param year
	 * @param season
	 * @return
	 */
	public List<Course> queryCoursesByYearAndSeason(int year, Season season);
	
	/**
	 * 多条件查询课程记录
	 * @param crsName
	 * @param year
	 * @param season
	 * @return
	 */
	public List<Course> queryCourses(String crsName, int year, Season season);
	
}

10. 业务逻辑层实现:

StudentServImpl:

package com.huey.mybatis.serv.impl;

import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import com.huey.mybatis.entity.Student;
import com.huey.mybatis.mapper.StudentMapper;
import com.huey.mybatis.serv.StudentServ;
import com.huey.mybatis.utils.MybatisUtil;

/**
 * 业务逻辑层实现StudentServImpl
 * @author huey2672
 * @version 1.0
 * @created 2014-7-25
 */
public class StudentServImpl implements StudentServ {

	private SqlSessionFactory sessionFactory = MybatisUtil.getSqlSessionFactory();
	
	@Override
	public int addStudent(Student student) {
		
		/**
		 * 每一个线程应该有它自己的SqlSession实例。
		 * SqlSession对象实例不是线程安全的,并且不被共享。
		 * 所以SqlSession的作用域最好就是其所在方法的作用域。
		 * 从Web应用程序角度上看,SqlSession应该存在于request级别作用域上。
		 */
		SqlSession session = sessionFactory.openSession();
		
		int count = 0;
		try {
			// 获取mapper
			StudentMapper studentMapper = session.getMapper(StudentMapper.class);
			// 
			count = studentMapper.addStudent(student);
			// 提交事务
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭资源
			session.close();
		}
		return count;
	}
	
	@Override
	public int deleteStudent(Integer studNo) {
		SqlSession session = sessionFactory.openSession();
		int count = 0;
		try {
			StudentMapper studentMapper = session.getMapper(StudentMapper.class);
			count = studentMapper.deleteStudent(studNo);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return count;
	}

	@Override
	public int updateStudent(Student student) {
		SqlSession session = sessionFactory.openSession();
		int count = 0;
		try {
			StudentMapper studentMapper = session.getMapper(StudentMapper.class);
			count = studentMapper.updateStudent(student);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return count;
	}	

	@Override
	public Student getStudent(Integer studNo) {
		SqlSession session = sessionFactory.openSession();
		Student student = null;
		try {
			StudentMapper studentMapper = session.getMapper(StudentMapper.class);
			student = studentMapper.getStudent(studNo);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return student;
	}

	@Override
	public List<Student> getAllStudents() {
		SqlSession session = sessionFactory.openSession();
		List<Student> students = new ArrayList<Student>();
		try {
			StudentMapper studentMapper = session.getMapper(StudentMapper.class);
			students = studentMapper.getAllStudents();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return students;
	}
	
	@Override
	public List<Student> pagingQueryStudents(int pageIndex, int pageSize) {
		SqlSession session = sessionFactory.openSession();
		List<Student> students = new ArrayList<Student>();
		try {
			StudentMapper studentMapper = session.getMapper(StudentMapper.class);
			// offset表示开始位置
			int offset = (pageIndex - 1) * pageSize;
			// limit表示要取的记录的数目
			int limit = pageSize;
			students = studentMapper.getAllStudents(new RowBounds(offset, limit));
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return students;
	}
	
}
TeacherServImpl:
package com.huey.mybatis.serv.impl;

import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import com.huey.mybatis.entity.Teacher;
import com.huey.mybatis.mapper.TeacherMapper;
import com.huey.mybatis.serv.TeacherServ;
import com.huey.mybatis.utils.MybatisUtil;

/**
 * 业务逻辑层实现TeacherServImpl
 * @author huey2672
 * @version 1.0
 * @created 2014-7-26
 */
public class TeacherServImpl implements TeacherServ {

	private SqlSessionFactory sessionFactory = MybatisUtil.getSqlSessionFactory();
	
	@Override
	public int addTeacher(Teacher teacher) {
		SqlSession session = sessionFactory.openSession();
		
		int count = 0;
		try {
			// 获取mapper
			TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);
			// 
			count = teacherMapper.addTeacher(teacher);
			// 提交事务
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭资源
			session.close();
		}
		return count;
	}

	@Override
	public int deleteTeacher(Integer tchId) {	
		SqlSession session = sessionFactory.openSession();
		
		int count = 0;
		try {
			TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);
			count = teacherMapper.deleteTeacher(tchId);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return count;
	}
	
	@Override
	public int updateTeacher(Teacher teacher) {
		SqlSession session = sessionFactory.openSession();
		
		int count = 0;
		try {
			TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);
			count = teacherMapper.updateTeacher(teacher);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return count;
	}

	@Override
	public Teacher getTeacher(Integer tchId) {
		SqlSession session = sessionFactory.openSession();
		Teacher teacher = null;
		try {
			TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);
			teacher = teacherMapper.getTeacher(tchId);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return teacher;
	}
	
	@Override
	public Teacher getTeacherWithCourses(Integer tchId) {
		SqlSession session = sessionFactory.openSession();
		Teacher teacher = null;
		try {
			TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);
			teacher = teacherMapper.getTeacherWithCourses(tchId);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return teacher;
	}
	
	@Override
	public List<Teacher> getAllTeachers() {
		SqlSession session = sessionFactory.openSession();
		List<Teacher> teachers = new ArrayList<Teacher>();
		
		try {
			TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);
			teachers = teacherMapper.getAllTeachers();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return teachers;
	}

}
CourseServImpl:
package com.huey.mybatis.serv.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import com.huey.mybatis.entity.Course;
import com.huey.mybatis.entity.Season;
import com.huey.mybatis.mapper.CourseMapper;
import com.huey.mybatis.serv.CourseServ;
import com.huey.mybatis.utils.MybatisUtil;

/**
 * 业务逻辑层实现CourseServImpl
 * @author huey2672
 * @version 1.0
 * @created 2014-7-28
 */
public class CourseServImpl implements CourseServ {

	private SqlSessionFactory sessionFactory = MybatisUtil.getSqlSessionFactory();
	
	@Override
	public int addCourse(Course course) {
		SqlSession session = sessionFactory.openSession();
		int count = 0;
		try {
			CourseMapper courseMapper = session.getMapper(CourseMapper.class);
			count = courseMapper.addCourse(course);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return count;
	}

	@Override
	public int deleteCourse(Integer crsId) {
		SqlSession session = sessionFactory.openSession();
		int count = 0;
		try {
			CourseMapper courseMapper = session.getMapper(CourseMapper.class);
			count = courseMapper.deleteCourse(crsId);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return count;
	}

	@Override
	public int updateCourse(Course course) {
		SqlSession session = sessionFactory.openSession();
		int count = 0;
		try {
			CourseMapper courseMapper = session.getMapper(CourseMapper.class);
			count = courseMapper.updateCourse(course);
			session.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return count;
	}
	
	@Override
	public Course getCourse(Integer crsId) {
		SqlSession session = sessionFactory.openSession();
		Course course = null;
		try {
			CourseMapper courseMapper = session.getMapper(CourseMapper.class);
			course = courseMapper.getCourse(crsId);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return course;
	}
	
	@Override
	public List<Course> getAllCourses() {
		SqlSession session = sessionFactory.openSession();
		List<Course> courses = new ArrayList<Course>();
		try {
			CourseMapper courseMapper = session.getMapper(CourseMapper.class);
			courses = courseMapper.getAllCourses();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return courses;
	}

	@Override
	public List<Course> queryCoursesByTchId(Integer tchId) {
		SqlSession session = sessionFactory.openSession();
		List<Course> courses = new ArrayList<Course>();
		try {
			CourseMapper courseMapper = session.getMapper(CourseMapper.class);
			courses = courseMapper.queryCoursesByTchId(tchId);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return courses;
	}
	
	@Override
	public List<Course> queryCoursesByYearAndSeason(int year, Season season) {
		SqlSession session = sessionFactory.openSession();
		List<Course> courses = new ArrayList<Course>();
		try {
			CourseMapper courseMapper = session.getMapper(CourseMapper.class);
			courses = courseMapper.queryCoursesByYearAndSeason(year, season);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return courses;
	}
	
	@Override
	public List<Course> queryCourses(String crsName, int year, Season season) {
		SqlSession session = sessionFactory.openSession();
		List<Course> courses = new ArrayList<Course>();
		try {
			CourseMapper courseMapper = session.getMapper(CourseMapper.class);
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("crsName", "%" + crsName + "%");
			params.put("year", year);
			params.put("season", season);
			courses = courseMapper.queryCourses(params);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			session.close();
		}
		return courses;
	}
	
}

11. log4j.properties配置:

log4j.rootLogger=debug, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n

log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.org.apache=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

12. 单元测试:

StudentServImplTest:

package com.huey.mybatis.serv.impl;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.junit.Test;

import com.huey.mybatis.entity.Student;
import com.huey.mybatis.serv.StudentServ;
import com.huey.mybatis.serv.impl.StudentServImpl;

/**
 * 单元测试类StudentServTest
 * 用于测试StudentServImpl中的方法
 * @author huey2672
 * @version 1.0
 * @created 2014-7-25
 */
public class StudentServImplTest {
	
	StudentServ studentServ = new StudentServImpl();
	
	/**
	 * 测试addStudent方法
	 * @throws Exception
	 */
	@Test
	public void testAddStudent() throws Exception {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Date birthday = sdf.parse("1900-01-01");
		Student student = new Student(10007, "孙悟空", birthday, "monkey@gamil.com");

		int result = studentServ.addStudent(student);
		System.out.println("result = " + result);
	}
	
	/**
	 * 测试deleteStudent方法
	 * @throws Exception
	 */
	@Test
	public void testDeleteStudent() throws Exception {
		int studNo = 10001;
		int result = studentServ.deleteStudent(studNo);
		System.out.println("result = " + result);
	}
	
	/**
	 * 测试updateStudent方法
	 * @throws Exception
	 */
	@Test
	public void testUpdateStudent() throws Exception {
		int studNo = 10001;
		Student student = studentServ.getStudent(studNo);
		if (student != null) {
			student.setEmail("zhangsan@gmail.com");
			int result = studentServ.updateStudent(student);
			System.out.println("result = " + result);
		} else {
			System.out.println("查询不到该学生记录");
		}
		
	}
	
	/**
	 * 测试getStudent方法
	 * @throws Exception
	 */
	@Test
	public void testGetStudent() throws Exception {
		int studNo = 10001;
		Student student = studentServ.getStudent(studNo);
		System.out.println(student);
	}
	
	/**
	 * 测试getAllStudents方法
	 * @throws Exception
	 */
	@Test
	public void testGetAllStudents() throws Exception {
		List<Student> students = studentServ.getAllStudents();
		for (Student student : students) {
			System.out.println(student);
		}
 	}
	
	@Test
	public void testPagingQueryStudents() throws Exception {
		int pageIndex = 2;
		int pageSize = 4;
		List<Student> students = studentServ.pagingQueryStudents(pageIndex, pageSize);
		for (Student student : students) {
			System.out.println(student);
		}
	}
	
}
TeacherServImplTest:
package com.huey.mybatis.serv.impl;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.junit.Test;

import com.huey.mybatis.entity.Course;
import com.huey.mybatis.entity.Teacher;
import com.huey.mybatis.entity.Tel;
import com.huey.mybatis.serv.TeacherServ;

/**
 * 单元测试类TeacherServImplTest
 * 用于测试TeacherServImpl中的方法
 * @author huey2672
 * @version 1.0
 * @created 2014-7-26
 */
public class TeacherServImplTest {

	TeacherServ teacherServ = new TeacherServImpl();
	
	/**
	 * 测试addTeacher方法
	 * @throws Exception
	 */
	@Test
	public void testAddTeacher() throws Exception {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Date birthday = sdf.parse("1977-07-07");
		Teacher teacher = new Teacher(10003, "孔子", birthday, new Tel("021-12345"));
		
		int result = teacherServ.addTeacher(teacher);
		System.out.println("result = " + result);
	}
	
	/**
	 * 测试deleteTeacher方法
	 * @throws Exception
	 */
	@Test
	public void testDeleteTeacher() throws Exception {
		int tchId = 10001;
		int result = teacherServ.deleteTeacher(tchId);
		System.out.println("result = " + result);
	}
	
	/**
	 * 测试updateTeacher方法
	 * @throws Exception
	 */
	@Test
	public void testUpdateTeacher() throws Exception {
		int tchId = 10001;
		Teacher teacher = teacherServ.getTeacher(tchId);		
		if (teacher != null) {
			teacher.setTel(new Tel("010-55555"));
			int result = teacherServ.updateTeacher(teacher);
			System.out.println("result = " + result);
		} else {
			System.out.println("查询不到该教师记录");
		}
		
	}
	
	/**
	 * 测试getTeacher方法
	 * @throws Exception
	 */
	@Test
	public void testGetTeacher() throws Exception {
		int tchId = 10001;
		Teacher teacher = teacherServ.getTeacher(tchId);
		System.out.println(teacher);
	}
	
	@Test
	public void testGeTeacherWithCourses() throws Exception {
		int tchId = 10001;
		Teacher teacher = teacherServ.getTeacherWithCourses(tchId);
		System.out.println(teacher);
		for (Course course : teacher.getCourses()) {
			System.out.println(course);
		}
	}
	
	/**
	 * 测试getAllTeachers方法
	 * @throws Exception
	 */
	@Test
	public void testGetAllTeachers() throws Exception {
		List<Teacher> teachers = teacherServ.getAllTeachers();
		for (Teacher teacher : teachers) {
			System.out.println(teacher);
		}
	}
	
}
CourseServImplTest:

package com.huey.mybatis.serv.impl;

import java.util.List;

import org.junit.Test;

import com.huey.mybatis.entity.Course;
import com.huey.mybatis.entity.Season;
import com.huey.mybatis.entity.Teacher;
import com.huey.mybatis.serv.CourseServ;
import com.huey.mybatis.serv.TeacherServ;

/**
 * 单元测试类CourseServImplTest
 * 用于测试CourseServImpl中的方法
 * @author huey2672
 * @version 1.0
 * @created 2014-7-28
 */
public class CourseServImplTest {

	CourseServ courseServ = new CourseServImpl();
	TeacherServ teacherServ = new TeacherServImpl();
	
	/**
	 * 测试addCourse方法
	 * @throws Exception
	 */
	@Test
	public void testAddCourse() throws Exception {
		Integer tchId = 10003;
		Teacher teacher = teacherServ.getTeacher(tchId);
		
		Course course = new Course(10005, "AJAX", "Asynchronous Javascript + XML",
				2014, Season.SPRING, teacher);
		int result = courseServ.addCourse(course);
		System.out.println("result = " + result);
	}
	
	/**
	 * 测试deleteCourse方法
	 * @throws Exception
	 */
	@Test
	public void testDeleteCourse() throws Exception {
		int crsId = 10001;
		int result = courseServ.deleteCourse(crsId);
		System.out.println("result = " + result);
	}
	
	/**
	 * 测试updateCourse方法
	 * @throws Exception
	 */
	@Test
	public void testUpdateCourse() throws Exception {
		int crsId = 10001;
		Course course = courseServ.getCourse(crsId);
		if (course != null) {
			course.setName("SQL");
			course.setDescription("Structured Query Language");
			int result = courseServ.updateCourse(course);
			System.out.println("result = " + result);
		} else {
			System.out.println("查询不到该课程记录");
		}
		
	}
	
	/**
	 * 测试getCourse方法
	 * @throws Exception
	 */
	@Test
	public void testGetCourse() throws Exception {
		int crsId = 10004;
		Course course = courseServ.getCourse(crsId);
		System.out.println(course);
	}
	
	/**
	 * 测试getAllCourses方法
	 * @throws Exception
	 */
	@Test
	public void testGetAllCourses() throws Exception {
		List<Course> courses = courseServ.getAllCourses();
		for (Course course : courses) {
			System.out.println(course);
		}
	}
	
	/**
	 * 测试queryCoursesByTchId方法
	 * @throws Exception
	 */
	@Test
	public void testQueryCoursesByTchId() throws Exception {
		int tchId = 10002;
		List<Course> courses = courseServ.queryCoursesByTchId(tchId);
		for (Course course : courses) {
			System.out.println(course);
		}
	}
	
	/**
	 * 测试queryCoursesByYearAndSeason方法
	 * @throws Exception
	 */
	@Test
	public void testQueryCoursesByYearAndSeason() throws Exception {
		int year = 2014;
		Season season = Season.SPRING;
		List<Course> courses = courseServ.queryCoursesByYearAndSeason(year, season);
		for (Course course : courses) {
			System.out.println(course);
		}
	}
	
	/**
	 * 测试queryCourses方法
	 * @throws Exception
	 */
	@Test
	public void testQueryCourses() throws Exception {
		String crsName = "Java";
		int year = 2013;
		Season season = null;
		List<Course> courses = courseServ.queryCourses(crsName, year, season);
		for (Course course : courses) {
			System.out.println(course);
		}
	}
	
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值