以前一直在使用spring的JDBCTEMPLATE和hibernate做项目;两个都还不错,spring的jdbctemplate用起来比较麻烦,虽然很简单。而hibernate呢,用起来很好用,很方便,但是很多规矩,规则还有方法到现在都还是入门阶段。所以我就学习了一下mybatis来充实一下自己。

mybatis的学习(我也只是入门),我参考了这个博客地址----大神的总结,通过对他的博客的一些学习,我做了一些自己的总结,所以下面的一些内容都是自己在学习的时候的一些东西,也是参考着大神的博客来做的。当然做了一些错误的修改和自己理解的实现。

mybatis实战教程(mybatis in action)之一:开发环境搭建

1.关于数据库表的创建,参见大神的博文,这里就不再多说;

2.在user_src下的Configuration.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><!--这里给我们要使用的数据实体类设置一个在mybatis中使用的别名,以后在mybatis中直接使用他们的别名来映射到对应的实体对象中 --><typeAliases><typeAlias alias="User" type="com.mpc.mybaits.model.User" /><typeAlias alias="Article" type="com.mpc.mybaits.model.Article" /></typeAliases><!-- 指定mybatis中使用的数据库环境,默认使用development,其中development使用的是JDBC来链接数据库,数据库是mysql --><environments default="development"><environment id="development"><transactionManager type="JDBC" /><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver" /><property name="url" value="jdbc:mysql://127.0.0.1:3306/mybaits" /><property name="username" value="root" /><property name="password" value="root" /></dataSource></environment></environments><!--这里使用mapper来指定相应的实体类的处理方法,(这些mapper就是处理数据的增删改查方法的xml集合,在这里面你可以写任何的查询方法 ,在这些xml中我们可以使用typeAliases中申明的对象来包装我们的查询结果,传入查询参数), 这写mapper都是可以写任意的查询方法的,(任意的表,任意的查询语句)但是在开发中我们为每一个类指定一个mapper文件,这样是为了方便管理和项目的开发 ;总之就是一点:mapper和typeAliases是没有任何对应关系的,只是为了开发方便才会有什么Usermapper、Articlemapper这些分类 --><mappers><mapper resource="com/mpc/mybaits/model/User.xml" /></mappers>
</configuration>

3.具体User类的实现参照大神的博文,我这里就不献丑了。只说一句:这个类是用在typeAliases那里的;

4.和User类在同一个包下的User.xml,这个User.xml是用在mappers中的,它的作用是提供数据库增删改查的方法。

<?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">
<!-- 这里我们要通过xml来进行数据库的操作,所以我饿美女给这个mapper指定一个唯一的空间名称, -->
<mapper namespace="com.mpc.mybaits.model.UserMapper"><!-- 这里定一个select方法,从user表中查找指定id的数据,然后用 resultType="User" User类来进行包装 --><!--  id是这个方法的唯一标识,通过id来调用这个方法,parameterType是传入的参数的类型,这里是整形。通过#{xxx}来获得传入的参数--><select id="selectUserByID" parameterType="int" resultType="User">select * from `user` where id = #{id}</select></mapper>

5.建立测试类

package com.mpc.test;import java.io.Reader;import lombok.Getter;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Assert;
import org.junit.Test;import com.mpc.mybaits.model.User;public class Test1 {private static @Getter SqlSessionFactory sqlSessionFactory;private static Reader reader;static {// 在一个static块中处理我们的相关初始化操作,这里做的操作是用Configuration.xml中的配置信息来初始化一个mybatis使用的sqlSessionFactorytry {reader = Resources.getResourceAsReader("Configuration.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);} catch (Exception e) {e.printStackTrace();}}@Testpublic void test() {SqlSession session = sqlSessionFactory.openSession();// 获得sessionAssert.assertNotNull(session);// 断言session不为空try {// 通过session来调用com.mpc.mybaits.model.UserMapper.selectUserByID方法,传入的参数是1// 其中com.mpc.mybaits.model.UserMapper是我们的mapper的命名空间。selectUserByID是方法的idUser user = (User) session.selectOne("com.mpc.mybaits.model.UserMapper.selectUserByID", 1);Assert.assertNotNull(user);// 断言user不为空Assert.assertEquals("User(id=1, userName=summer, userAge=100, userAddress=shanghai,pudong)",user.toString());// 对user内容的断言} finally {session.close();// 最后要关闭session}}// public static void main(String[] args) {// SqlSession session = sqlSessionFactory.openSession();// try {// User user = (User) session.selectOne(// "com.mpc.mybaits.model.UserMapper.selectUserByID", 1);// System.out.println(user.toString());// } finally {// session.close();// }// }
}

测试结果:

mybatis实战教程(mybatis in action)之二:以接口的方式编程

使用接口编程的方式可以提高我们在方法中使用mybatis的效率,减少很多不必要错误,让我们不用总是查来查去,思来想去。。

1.在inter包中定义我们的接口

package com.mpc.mybaits.inter;import java.util.List;
import java.util.Map;import org.apache.ibatis.annotations.Param;import com.mpc.mybaits.model.Article;
import com.mpc.mybaits.model.User;
import com.mpc.mybaits.utils.PageInfo;/*** @author Administrator**/
public interface IUserOperation {/*** 方法的名称必须与User。xml中的 select 的id 对应(<select id="selectUserByID")* * @param id* @return*/public User selectUserByID(int id);}

2.修改user.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="ccom.mpc.mybaits.inter.IUserOperation"><!-- 这里定一个select方法,从user表中查找指定id的数据,然后用 resultType="User" User类来进行包装 --><!--  id是这个方法的唯一标识,通过id来调用这个方法,parameterType是传入的参数的类型,这里是整形。通过#{xxx}来获得传入的参数--><select id="selectUserByID" parameterType="int" resultType="User">select * from `user` where id = #{id}</select></mapper>

3.测试方法

package com.mpc.test;import java.io.Reader;import lombok.Getter;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import com.mpc.mybaits.inter.IUserOperation;
import com.mpc.mybaits.model.User;public class Test2 {private static @Getter SqlSessionFactory sqlSessionFactory;private static Reader reader;static {try {reader = Resources.getResourceAsReader("Configuration.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);} catch (Exception e) {e.printStackTrace();}}@Testpublic void test() {new Test1();SqlSession session = sqlSessionFactory.openSession();try {IUserOperation iUserOperation = session.getMapper(IUserOperation.class);//通过session来获得IUserOperation的实例对象User user = iUserOperation.selectUserByID(1);//直接调用接口中 的方法就可以了System.out.println(user.toString());} finally {session.close();}}
}

测试结果:

mybatis实战教程(mybatis in action)之三:实现数据的增删改查

*用list来返回多个查询结果,要使用list来返回多个查询结果,那么我们要定义自己的resultMap;

在User.xml中加入自己定义的resultMap;

 <!-- 为了返回list 类型而定义的returnMap --><resultMap type="User" id="resultListUser"><id column="id" property="id" /><result column="userName" property="userName" /><result column="userAge" property="userAge" /><result column="userAddress" property="userAddress" /></resultMap>

这是大神的博文中提到的,但是根据我自己的实践···这里完全没有必要使用resultMap,使用resultType就可以达到目的,所以我在user.xml中使用如下语句也是可以的:

 <select id="selectUsers" parameterType="string" resultType="User">select * from user where userName like #{userName}</select>

当然按照大神的博文中记载的方式也是可以的--》在User.xml中加入新的查询语句;

 <!-- 返回list 的select 语句,注意 resultMap 的值是指向前面定义好的 --><select id="selectUsers" parameterType="string" resultMap="resultListUser">select * from user where userName like #{userName}</select>

个人理解,resultMap就是我们自己定义的一种返回结果的包装,在从表中查处数据口,MyBatis把所有的查询结果都放在一个map中,都是用key-value的形式存放的,如果指定的是resultType,那么Mybatis会为我们进行封装,指定的为resultMap的话,Mabatis会按照resultMap定义的格式来进行封装而已-----------;

在IUserOperation接口中加入resulListUser这个id对应的接口方法----

public List<User> selectUsers(String userName);

测试方法:

package com.mpc.test;import java.io.Reader;
import java.util.List;import lombok.Getter;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;import com.mpc.mybaits.inter.IUserOperation;
import com.mpc.mybaits.model.User;public class Test2 {private static @Getter SqlSessionFactory sqlSessionFactory;private static Reader reader;static {try {reader = Resources.getResourceAsReader("Configuration.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);} catch (Exception e) {e.printStackTrace();}}@Testpublic void test() {new Test1();SqlSession session = sqlSessionFactory.openSession();try {IUserOperation iUserOperation = session.getMapper(IUserOperation.class);// 通过session来获得IUserOperation的实例对象List<User> list = iUserOperation.selectUsers("%");for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i).toString());}} finally {session.close();}}
}

测试结果:

*使用mybatis来增加数据

在User.xml中添加如下代码:

 <!--执行增加操作的SQL语句。id和parameterType 分别与IUserOperation接口中的addUser方法的名字和 参数类型一致。以#{name}的形式引用Student参数 的name属性,MyBatis将使用反射读取Student参数 的此属性。#{name}中name大小写敏感。引用其他 的gender等属性与此一致。seGeneratedKeys设置 为"true"表明要MyBatis获取由数据库自动生成的主 键;keyProperty="id"指定把获取到的主键值注入 到Student的id属性 --><insert id="addUser" parameterType="User" useGeneratedKeys="true"keyProperty="id">insert into user(userName,userAge,userAddress)values(#{userName},#{userAge},#{userAddress})</insert>

在IUserOperation接口中加入addUser这个id所对应的接口方法public void addUser(User user);

Mybatis在接受到user对象以后,会把user的属性都封装到一个map中,key是user的属性名,value就是user的属性值了。所在通过#{属性名}在user.xml中就能取得传入的user的属性值。

测试方法:

package com.mpc.test;import java.io.Reader;import lombok.Getter;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import com.mpc.mybaits.inter.IUserOperation;
import com.mpc.mybaits.model.User;public class Test3 {private static @Getter SqlSessionFactory sqlSessionFactory;private static Reader reader;static {try {reader = Resources.getResourceAsReader("Configuration.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {User user = new User();user.setUserAddress("人民广场123");user.setUserName("飞鸟123");user.setUserAge("80123");SqlSession session = sqlSessionFactory.openSession();try {IUserOperation iUserOperation = session.getMapper(IUserOperation.class);iUserOperation.addUser(user);session.commit();// 必须的,不然的话是保存不到数据库中的System.out.println("添加了用户,当前用户的id为" + user.getId());} finally {session.close();}}
}

测试结果:

*使用mybatis来更新数据

在User.xml中添加如下代码

 <update id="updateUser" parameterType="User">update user setuserName=#{userName},userAge=#{userAge},userAddress=#{userAddress}where id=#{id}</update>

在IUserOperation中添加对应的接口方法

public void updateUser(User user);

测试方法

package com.mpc.test;import java.io.Reader;import lombok.Getter;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import com.mpc.mybaits.inter.IUserOperation;
import com.mpc.mybaits.model.User;public class Test4 {private static @Getter SqlSessionFactory sqlSessionFactory;private static Reader reader;static {try {reader = Resources.getResourceAsReader("Configuration.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {SqlSession session = sqlSessionFactory.openSession();try {IUserOperation iUserOperation = session.getMapper(IUserOperation.class);User user = iUserOperation.selectUserByID(6);user.setUserAddress("太平天国");iUserOperation.updateUser(user);session.commit();// 必须的,不然的话是保存不到数据库中的System.out.println("更新了用户,当前用户的id为" + user.getId());} finally {session.close();}}
}

测试结果

*mybatis删除数据

在User.xml中添加如下代码

 <delete id="deleteUser" parameterType="int">delete from user whereid=#{id}</delete>

在IUserOperaiton中添加对应的接口方法:

 public void deleteUser(int id);

测试方法:

package com.mpc.test;import java.io.Reader;import lombok.Getter;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import com.mpc.mybaits.inter.IUserOperation;
import com.mpc.mybaits.model.User;public class TestDelete {private static @Getter SqlSessionFactory sqlSessionFactory;private static Reader reader;static {try {reader = Resources.getResourceAsReader("Configuration.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {SqlSession session = sqlSessionFactory.openSession();try {IUserOperation iUserOperation = session.getMapper(IUserOperation.class);User user = iUserOperation.selectUserByID(4);iUserOperation.deleteUser(6);session.commit();// 必须的,不然的话是保存不到数据库中的System.out.println("删除了用户,当前用户的id为" + user.getId());} finally {session.close();}}
}

mybatis实战教程(mybatis in action)之四:实现关联数据的查询

1.article表和实体的创建参加大神的博文,这里我就不写了。

2.在User.xml中添加如下代码

 <!-- User 联合文章进行查询 方法之一的配置 (多对一的方式) --><resultMap id="resultUserArticleList" type="Article"><id property="id" column="aid" /><result property="title" column="title" /><result property="content" column="content" /><association property="user" javaType="User"><id property="id" column="id" /><result property="userName" column="userName" /><result property="userAddress" column="userAddress" /><result property="userAge" column="userAge" /></association><!-- <association property="user" javaType="User" resultMap="resultListUser" /> --></resultMap>

这里要使用到resultMap,因为我们的数据库中的表结构和我们自己定义的类的字段是不对应的,通过联合查询以后,mybatis并不知道要用怎样的映射关系来专配,所以我们在这里自己定义。

在User.xml中加入查询代码

 <select id="getUserArticles" parameterType="int"resultMap="resultUserArticleList">select user.id,user.userName,user.userAddress,user.userAge,article.idaid,article.title,article.content from user,articlewhereuser.id=article.userid and user.id=#{id}</select>

3.在IUserOperation中加入相应的接口方法

public List<Article> getUserArticles(int userid);

4.测试方法

package com.mpc.test;import java.io.Reader;
import java.util.List;import lombok.Getter;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import com.mpc.mybaits.inter.IUserOperation;
import com.mpc.mybaits.model.Article;
import com.mpc.mybaits.model.User;public class Test5 {private static @Getter SqlSessionFactory sqlSessionFactory;private static Reader reader;static {try {reader = Resources.getResourceAsReader("Configuration.xml");sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {SqlSession session = sqlSessionFactory.openSession();try {IUserOperation iUserOperation = session.getMapper(IUserOperation.class);List<Article> articles = iUserOperation.getUserArticles(1);System.out.println(articles.size());for (Article article : articles) {System.out.println(article.getUser().toString());System.out.println(article.getTitle() + ":"+ article.getContent() + ":作者是:"+ article.getUser().getUserName() + ":地址:"+ article.getUser().getUserAddress());}} finally {session.close();}}
}

5.测试结果

也可以在已经定义好user的resultMap的情况下,在association处直接使用

<association property="user" javaType="User" resultMap="resultListUser" />

来做关联查询,这个大神博文中有,我就不做解释了。

mybatis实战教程(mybatis in action)之五:与spring3集成
mybatis实战教程(mybatis in action)之六:与Spring MVC 的集成
mybatis SqlSessionDaoSupport的使用

在大神的博文中,这三个是分开写的,这里我就整合到一起了,使用spring,一般也会用springmvc。然后SqlSessionDaoSupport这个的话,我觉得没必要去在乎,可以直接实现dao就可以了,具体实现如下:

具体的项目结构如下图所示:

1.修改web.xml来进行spring和pringmvc的配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"><!-- log4j配置文件 --><context-param><param-name>log4jConfigLocation</param-name><param-value>classpath:/config/log4j.properties</param-value></context-param><!-- Spring的log4j监听器 --><listener><listener-class>org.springframework.web.util.Log4jConfigListener</listener-class></listener><!--配置参数 和具体项目没有关系 在容器初始化项目还没有启动执行--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:/config/*.xml</param-value></context-param><!-- 维护ioc  --><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- 可以使用RequestContextHolder.currentRequestAttributes() 获取到请求的attr --><listener><listener-class>org.springframework.web.context.request.RequestContextListener</listener-class></listener><!-- 前端核心分发器 --><servlet><servlet-name>dispatcher</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--业务控制器配置文件 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:/config/spring-mvc-servlet.xml</param-value></init-param><load-on-startup>2</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcher</servlet-name><!-- <url-pattern>*.do</url-pattern>--><!-- 配置为/ 不带文件后缀,会造成其它静态文件(js,css等)不能访问。如配为*.do,则不影响静态文件的访问 --><url-pattern>/</url-pattern></servlet-mapping><!-- pushlet 推送 <servlet><servlet-name>pushlet</servlet-name><servlet-class>nl.justobjects.pushlet.servlet.Pushlet</servlet-class><load-on-startup>3</load-on-startup></servlet><servlet-mapping><servlet-name>pushlet</servlet-name><url-pattern>/pushlet.srv</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><session-config><session-timeout>30</session-timeout></session-config><error-page><error-code>500</error-code><location>/500.html</location></error-page><error-page><error-code>404</error-code><location>/404.html</location></error-page></web-app>

2.配置config包下的applicationContext.xml的内容,这个xml文件包含了所有关于spring的配置。

<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:context="http://www.springframework.org/schema/context"xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-3.0.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"default-lazy-init="false"><!-- 加载properties文件到spring中,方便在spring中使用 --><bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="locations"><list><value>classpath:/config/jdbc.properties</value></list></property></bean><!-- 使用jdbc来链接数据库,创建数据源 --><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close"><property name="driverClassName" value="${connection.driverClassName}" /><property name="url" value="${connection.url}" /><property name="username" value="${connection.username}" /><property name="password" value="${connection.password}" /><property name="maxActive" value="${connection.maxActive}" /><property name="maxIdle" value="${connection.maxIdle}" /><property name="minIdle" value="${connection.minIdle}" /><property name="removeAbandoned" value="${connection.removeAbandoned}" /><property name="removeAbandonedTimeout" value="${connection.removeAbandonedTimeout}" /><property name="logAbandoned" value="${connection.logAbandoned}" /><property name="defaultAutoCommit" value="${connection.defaultAutoCommit}" /><property name="defaultReadOnly" value="${connection.defaultReadOnly}" /></bean><!--配置事务管理器 --><bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /></bean><!-- 这里我在原来博文的基础上加入了spring的aop事务管理 --><aop:config><!-- 设置pointCut表示哪些方法要加入事务处理 --><!-- 以下的事务是声明在DAO中,但是通常都会在Service来处理多个业务对象逻辑的关系,注入删除,更新等,此时如果在执行了一个步骤之后抛出异常 就会导致数据不完整,所以事务不应该在DAO层处理,而应该在service,这也就是Spring所提供的一个非常方便的工具,声明式事务 --><aop:pointcut id="txPointcut"expression="execution(* com.mpc.*.service..*.*(..))" /><!-- 通过advisor来确定具体要加入事务控制的方法 --><aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" /></aop:config><!-- 配置哪些方法要加入事务控制 --><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="get*" propagation="REQUIRED" read-only="true" /><tx:method name="count*" propagation="REQUIRED" read-only="true" /><tx:method name="find*" propagation="REQUIRED" read-only="true" /><tx:method name="list*" propagation="REQUIRED" read-only="true" /><tx:method name="*" propagation="REQUIRED" read-only="true" /><!-- 一下方法都是可能设计修改的方法,无法设置为只读 --><tx:method name="add*" propagation="REQUIRED" /><tx:method name="create*" propagation="REQUIRED" /><tx:method name="insert*" propagation="REQUIRED" /><tx:method name="merge*" propagation="REQUIRED" /><tx:method name="del*" propagation="REQUIRED" /><tx:method name="remove*" propagation="REQUIRED" /><tx:method name="put*" propagation="REQUIRED" /><tx:method name="update*" propagation="REQUIRED" /><tx:method name="save*" propagation="REQUIRED" /><!-- 这个hhh是我测试在aop事务和mybatis配合的时候,事务是否生效 --><tx:method name="hhh*" propagation="REQUIRED" /></tx:attributes></tx:advice><!-- 下面是mybatis的相关配置,这些都需要导入jar包,mybaits-spring.jar,这个在我参考的博文中有,我就不多说了 --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!--dataSource属性指定要用到的连接池 --><property name="dataSource" ref="dataSource" /><!--configLocation属性指定mybatis的核心配置文件 --><property name="configLocation" value="classpath:/config/Configuration.xml" /><!-- 这里指定了我们的User.xml这类规定数据库操作的xml文件的位置,在项目中独立把他们放到了一个mapper包下 --><property name="mapperLocations" value="classpath*:com/mpc/mybaits/mapper/*.xml" /></bean><!-- 这个就是用接口变成的方式中,指定从哪里扫描我们的接口,托管到spring中管理,这样在spring的service或dao中就可以使用了 --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.mpc.mybaits.inter" /></bean><!-- <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> sqlSessionFactory属性指定要用到的SqlSessionFactory实例 <property name="sqlSessionFactory" ref="sqlSessionFactory" /> mapperInterface属性指定映射器接口,用于实现此接口并生成映射器对象 <property name="mapperInterface" value="com.mpc.mybaits.inter.IUserOperation" /> </bean> --><context:component-scan base-package="com.mpc.mybaits"><!-- 注意在这里扫描的时候不要扫描controller,因为在这里装载了controller的话 controller获得的service和dao就是没有事务的--><context:exclude-filter type="annotation"expression="org.springframework.stereotype.Controller" /><!-- secuirty模块需要 --><context:exclude-filter type="annotation"expression="org.springframework.web.bind.annotation.ControllerAdvice" /></context:component-scan>
</beans>

3.配置config下的spring-mvc-servlet.xml,这xml文件是用来配置springmvc的,主要包括视图的解析以及相关请求的配置

<?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:context="http://www.springframework.org/schema/context"xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-3.2.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsdhttp://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.2.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"default-lazy-init="false"><bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver" /><!-- 默认的视图解析器 --><bean id="defaultViewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver"p:order="3"><!-- 如果使用freemaker 或者velocity 需要更改viewClass --><property name="viewClass"value="org.springframework.web.servlet.view.JstlView" /><property name="contentType" value="text/html" /><property name="prefix" value="/WEB-INF/view/" /><property name="suffix" value=".jsp" /></bean><!-- 开启controller注解支持 --><!-- 注:如果base-package=com.mpc 则注解事务不起作用 TODO 读源码 --><context:component-scan base-package="com.mpc.mybaits"use-default-filters="false"><!-- 在这里扫描controller,controller就能获得有事务的service和dao --><context:include-filter type="annotation"expression="org.springframework.stereotype.Controller" /><!-- security 模块需要 --><context:include-filter type="annotation"expression="org.springframework.web.bind.annotation.ControllerAdvice" /></context:component-scan><!-- 开启注解 --><mvc:annotation-driven /><!-- 在配置为/的时候,静态文件的访问会有问题,配置了这个以后,就不会有问题了 --><mvc:default-servlet-handler />
</beans>

4.config下的Configuration.xml,这个就是我们的mybatis的核心配置文件,是session的配置信息,由于很多功能托管给了spring,所以变的很瘦小

<?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><typeAliases><typeAlias alias="User" type="com.mpc.mybaits.model.User" /><typeAlias alias="Article" type="com.mpc.mybaits.model.Article" /></typeAliases><!-- 数据源的相关配置已经托管给了spring --><!-- <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybaits" /> <property name="username" value="root" /> <property name="password" value="root" /> </dataSource> </environment> </environments> --><!-- mappers的配置托管给了spring --><!-- <mappers> <mapper resource="com/mpc/mybaits/model/User.xml" /> </mappers> -->
</configuration>

5.DAO层的实现

package com.mpc.mybaits.dao;import java.util.List;import com.mpc.mybaits.model.Article;
import com.mpc.mybaits.model.User;public interface UserDAO {public List<Article> getUserArticles(int userid);public User hhhh(User user);
}
package com.mpc.mybaits.dao.impl;import java.util.List;import javax.annotation.Resource;import org.springframework.stereotype.Repository;import com.mpc.mybaits.dao.UserDAO;
import com.mpc.mybaits.inter.IUserOperation;
import com.mpc.mybaits.model.Article;
import com.mpc.mybaits.model.User;//规定这个是dao层的组件
@Repository
public class UserDaoImpl implements UserDAO {// 注入我们在inter中实现的接口@Resourceprivate IUserOperation iUserOperation;@Overridepublic List<Article> getUserArticles(int userid) {// 通过在dao中直接使用我们在inter中实现的接口就可以在遵循spring的规范来使用mybaits了return iUserOperation.getUserArticles(userid);}@Overridepublic User hhhh(User user) {iUserOperation.addUser(user);return user;}}

6.service层的实现

package com.mpc.mybaits.service;import java.util.List;import com.mpc.mybaits.model.Article;
import com.mpc.mybaits.model.User;public interface UserService {public List<Article> getUserArticles(int userid);public User hhhh(User user);
}
package com.mpc.mybaits.service.impl;import java.util.List;import javax.annotation.Resource;import org.springframework.stereotype.Service;import com.mpc.mybaits.dao.UserDAO;
import com.mpc.mybaits.model.Article;
import com.mpc.mybaits.model.User;
import com.mpc.mybaits.service.UserService;@Service
public class UserServiceImpl implements UserService {@Resourceprivate UserDAO userDao;@Overridepublic List<Article> getUserArticles(int userid) {return userDao.getUserArticles(userid);}@Overridepublic User hhhh(User user) {// TODO Auto-generated method stubreturn userDao.hhhh(user);}}

7.controller层的实现

package com.mpc.mybaits.controller;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.mpc.mybaits.inter.IUserOperation;
import com.mpc.mybaits.model.Article;
import com.mpc.mybaits.model.User;
import com.mpc.mybaits.service.UserService;
import com.mpc.mybaits.utils.PageInfo;/*** @author Administrator**/
@Controller
@RequestMapping("/article")
public class UserController {@ResourceUserService userService;@RequestMapping("/listspring")@ResponseBodypublic List<Article> listallSpring(HttpServletRequest request,HttpServletResponse response) {List<Article> articles = userService.getUserArticles(1);return articles;}}

8.启动项目,测试结果:

mybatis实战教程(mybatis in action)之七:实现mybatis分页

1.按照我参考的博文的相关内容给util包中添加PageInfo、PagePlugin、ReflectHelper这三个类以后,就给代码中添加了分页插件。

2.在user.xml中添加如下代码

 <!-- 分页查询测试 --><select id="selectArticleListPage" resultMap="resultUserArticleList">selectuser.id,user.userName,user.userAddress,article.idaid,article.title,article.content from user,articlewhereuser.id=article.userid and user.id=#{userid}</select>

3.给inter包的接口中添加相应的方法

 public List<Article> selectArticleListPage(@Param("page") PageInfo page,@Param("userid") int userid);

4.在Configuration.xml中添加插件

 <plugins><plugin interceptor="com.mpc.mybaits.utils.PagePlugin"><property name="dialect" value="mysql" /><property name="pageSqlId" value=".*ListPage.*" /></plugin></plugins>

这样所有包含ListPage的mapper中的方法都会执行分页动作。

5.在controller中添加如下方法测试

 @RequestMapping("/listpage")public @ResponseBody List<Article> listpage(HttpServletRequest request,HttpServletResponse response) {int currentPage = (request.getParameter("page") == null || Integer.parseInt(request.getParameter("page")) <= 0) ? 1 : Integer.parseInt(request.getParameter("page"));int pageSize = 2;int currentResult = (currentPage - 1) * pageSize;System.out.println(request.getRequestURI());System.out.println(request.getQueryString());PageInfo info = new PageInfo();info.setShowCount(pageSize);info.setCurrentResult(currentResult);List<Article> list = userMapper.selectArticleListPage(info, 1);System.out.println(info);int totalCount = info.getTotalResult();int lastPage = 0;if (totalCount % pageSize == 0) {lastPage = totalCount / pageSize;} else {lastPage = 1 + totalCount / pageSize;}if (currentPage >= lastPage) {currentPage = lastPage;}String pageStr = "";// pageStr = String.format(// "<a href=\"%s\">上一页</a>    <a href=\"%s\">下一页</a>",// request.getRequestURI() + "?page=" + (currentPage - 1),// request.getRequestURI() + "?page=" + (currentPage + 1));//// ModelAndView mav = new ModelAndView("list");// mav.addObject("articles", list);// mav.addObject("pageStr", pageStr);// return mav;return list;}

6.测试结果

我规定的是一页显示两条,查询结果如下:

确实是两条,而我的数据库中有3条数据的。

mybatis实战教程(mybatis in action)之八:mybatis 动态sql语句(这部分貌似和分页一样··没有自己的一些感觉,只是在照猫画虎的学习一些语法来完成动态语句,参照的博客原文中介绍的都很详细了,这里我只是想记录一下自己足迹,不爱的同学可以跳过这一段)

1.mybatis if语句处理

在User.xml中添加如下代码,用来测试if语句

 <select id="selectUsersInCondition" parameterType="User"resultMap="resultListUser">select * from user where<if test="userAge !=null">userAge=#{userAge}</if><!-- 自己修改修改··因为如果传入的userAge是null的话,语句就变成了 and userAddress=xxxx,所以多了些判断,往后才知道·原来这种不靠谱的情况有其他解决方式 --><if test="userAddress !=null and userAge!=null">and userAddress=#{userAddress}</if><if test="userAddress !=null and userAge==null">userAddress=#{userAddress}</if></select>

在IUserOperation中添加相应的接口方法

public List<User> selectUsersInCondition(User user);

在controller中添加测试方法

 /*** @return 测试if动态查询*/@RequestMapping("/listusercon")@ResponseBodypublic List<User> listUserCon() {User user = new User();// user.setUserAge("100");user.setUserAddress("shanghai,pudong");return userMapper.selectUsersInCondition(user);}

测试结果


2.choose (when,otherwize)只走其中一条路

在User.xml中添加如下代码

 <select id="dynamicChooseTest" parameterType="User" resultMap="resultListUser">select * from user where<choose><when test="userAddress != null">userAddress=#{userAddress}</when><when test="userAge != null">userAge = #{userAge}</when><otherwise>id=1</otherwise></choose></select>

当传如的user对象的userAddress不为空就根据userAddress查询,userAge不为空就根据userAge查询,otherwise在所有的when都不满足的时候生效。但是永远只能选一个。

在IUserOperation中添加如下语句

public List<User> dynamicChooseTest(User user);

测试方法

 @RequestMapping("/listuserwhere")@ResponseBodypublic List<User> listUserWhere() {User user = new User();// user.setUserAge("100");// user.setUserAddress("shanghai,pudong");return userMapper.dynamicChooseTest(user);}

测试结果


可以看到的是在userAge,userAddress都为空的情况下,根据id=1来查询的

3.trim (对包含的内容加上 prefix,或者 suffix 等,前缀,后缀)

trim的作用就是可以为<trim></trim>标签所包含的内容加上一个前缀或者后缀,并且可以指定这个前缀或者后缀覆盖住指定的字符串。

在User.xml中添加如下代码

 <select id="dynamicTrimTest" parameterType="User" resultMap="resultListUser">select * from user<trim prefix="where" prefixOverrides="and |or"><if test="userAge != null">and userAge = #{userAge}</if><if test="userAddress != null">and userAddress = #{userAddress}</if></trim></select>

这样写的话,就算是userAge不是空的,那么出现在where后面的也是 userAge=xxx不是and userAge=xxx;

在IUserOperation中添加对应的接口方法;

public List<User> dynamicTrimTest(User user);

测试方法

 @RequestMapping("/listusertrim")@ResponseBodypublic List<User> listUserTrim() {User user = new User();// user.setUserAge("110");user.setUserAddress("shanghai,pudong");return userMapper.dynamicTrimTest(user);}

测试结果

可以看到,并没有报sql语句错误,trim是成功的。

4. where (主要是用来简化sql语句中where条件判断的,能智能的处理 and or 条件)

个人理解就是<where> ====<trim prefix="where" prefixOverrides="and |or">

在User.xml中添加如下代码

 <select id="dynamicWhereTest" parameterType="User" resultMap="resultListUser">select * from user<where><if test="userAge != null">and userAge = #{userAge}</if><if test="userAddress != null">and userAddress = #{userAddress}</if></where></select>

在IUserOperation中添加对应的接口方法

public List<User> dynamicWhereTest(User user);

测试方法:

 @RequestMapping("/listuserauto")@ResponseBodypublic List<User> listUserAuto() {User user = new User();// user.setUserAge("110");user.setUserAddress("shanghai,pudong");return userMapper.dynamicWhereTest(user);}

测试结果

5.set (主要用于更新时)

在User.xml中添加如下代码

 <update id="dynamicSetTest" parameterType="User">update user<set><if test="userAge != null">userAge = #{userAge},</if><if test="userAddress != null">userAddress = #{userAddress},</if></set>where id = #{id}</update>

<set>可以智能处理最后一个多出来的逗号

在IUserOperation中添加对应的接口方法

public void dynamicSetTest(User user);

测试方法

 @RequestMapping("/dynamicSetTest")@ResponseBodypublic User dynamicSetTest() {User user = new User();user.setId(1);user.setUserAge("120");user.setUserAddress("shanghai,pudong,laolao");userMapper.dynamicSetTest(user);return user;}

6. foreach (在实现 mybatis in 语句查询时特别有用)

6.1但参数List类型

在User.xml中的配置内容如下:

 <select id="dynamicForeachTest" resultMap="resultUserArticleList">selectuser.id,user.userName,user.userAddress,user.userAge,article.idaid,article.title,article.content from user,articlewhereuser.id=article.userid and article.userid in<foreach collection="list" index="index" item="item" open="("separator="," close=")">#{item}</foreach></select>

在IUserOperation中添加对应的接口方法

public List<Article> dynamicForeachTest(List<Integer> ids);

测试方法

 @RequestMapping("/dynamicForeachTest")@ResponseBodypublic List<Article> dynamicForeachTest() {List<Integer> list = new ArrayList<Integer>();list.add(1);list.add(3);return userMapper.dynamicForeachTest(list);}

测试结果

6.2数组类型的参数

在User.xml添加如下代码

 <select id="dynamicForeach2Test" resultMap="resultUserArticleList">selectuser.id,user.userName,user.userAddress,user.userAge,article.idaid,article.title,article.content from user,articlewhereuser.id=article.userid and article.userid in<foreach collection="array" index="index" item="item" open="("separator="," close=")">#{item}</foreach></select>

在IUserOperation中添加对应的接口方法

public List<Article> dynamicForeach2Test(int[] ids);

测试方法

 @RequestMapping("/dynamicForeach2Test")@ResponseBodypublic List<Article> dynamicForeach2Test() {int[] ints = new int[] { 1, 3 };return userMapper.dynamicForeach2Test(ints);}

测试结果

只是查询参数用数组来传入了,查询结果和list传入参数的结果是一样的

6.3map类型的参数,用map类型的参数可以传入多个参数,其中一个用来迭代

在User.xml中添加如下代码,使用map来传递参数,那么参数的key值是很有用的,通过id这个key来获得id的value值,通过指定collection为ids,从而迭代ids这个key所指定的value值。

 <select id="dynamicForeach3Test" resultMap="resultUserArticleList">selectuser.iduid,user.userName,user.userAddress,user.userAge,article.idaid,article.title,article.content from user,articlewherearticle.userid=#{id}and user.id=article.userid and article.userid in<foreach collection="ids" index="index" item="item" open="("separator="," close=")">#{item}</foreach></select>

在IUserOperation中添加对应的接口方法

public List<Article> dynamicForeach3Test(Map<String, Object> params);

测试方法

 @RequestMapping("/dynamicForeach3Test")@ResponseBodypublic List<Article> dynamicForeach3Test() {Map<String, Object> map = new HashMap<String, Object>();int[] ints = new int[] { 1, 3 };map.put("id", 1);map.put("ids", ints);return userMapper.dynamicForeach3Test(map);}

测试结果

mybatis实战教程(mybatis in action)之九:mybatis 代码生成工具的使用

这方面的内容按照参考博客中大神的方法,把各种信息本地化成自己的,就直接运行程序后,我们的各种类和xml文件就自动生成到自己的包里了,这里我就不烦人了。

总结:通过参照高手的博客,可以说对mybatis有了一个很基础的入门,知道了基本的使用技能,很多的使用技巧和高级的使用方法在以后项目的实践中还需要自己慢慢的积累和摸索。

mybatis自己学习的一些总结相关推荐

  1. Spring+SpringMVC+MyBatis深入学习及搭建(十)——MyBatis逆向工程

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6973266.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(九)--My ...

  2. java学mybatis还用学jdbc吗,mybatis系统学习(二)——使用基础mybatis代替原始jdbc

    mybatis系统学习(二)--使用基础mybatis代替原始jdbc 前言 这一篇笔记的内容应当是建立在上一篇的基础之上,不论是使用的数据表,还是对应的实体类,都在上一篇有过说明. 有兴趣的或者对相 ...

  3. Spring+SpringMVC+MyBatis深入学习及搭建(十一)——SpringMVC架构

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6985816.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十)--My ...

  4. Spring+SpringMVC+MyBatis深入学习及搭建(十七)——SpringMVC拦截器

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7098753.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十六)--S ...

  5. Spring+SpringMVC+MyBatis深入学习及搭建(十四)——SpringMVC和MyBatis整合

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7010363.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(十三)--S ...

  6. mybatis框架--学习笔记(下)

    上篇:mybatis框架--学习笔记(上):https://blog.csdn.net/a745233700/article/details/81034021 8.高级映射: (1)一对一查询: ①使 ...

  7. mybatis框架--学习笔记(上)

    使用JDBC操作数据库的问题总结: (1)数据库连接,使用时创建,不使用时立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响数据库性能. 设想:使用数据库连接池管理数据库连接. (2) ...

  8. Spring+SpringMVC+MyBatis深入学习及搭建(二)——MyBatis原始Dao开发和mapper代理开发

    前面有写到Spring+SpringMVC+MyBatis深入学习及搭建(一)--MyBatis的基础知识.MybatisFirst中存在大量重复的代码.这次简化下代码: 使用MyBatis开发Dao ...

  9. [Spring+SpringMVC+Mybatis]框架学习笔记(四):Spring实现AOP

    上一章:[Spring+SpringMVC+Mybatis]框架学习笔记(三):Spring实现JDBC 下一章:[Spring+SpringMVC+Mybatis]框架学习笔记(五):SpringA ...

最新文章

  1. vc++向txt文件中写入数据,追加数据
  2. Android View篇之自定义验证码输入框
  3. grpc在java中使用
  4. 网络知识:电脑无线网连接不上问题汇总!
  5. jetty9更改post请求长度
  6. flowable DMN部署单独使用_06
  7. collections 使用教程
  8. python生成泊松分布_Python Numpy泊松分布
  9. 拥有百万粉丝的大牛讲述学Android的历程程。看看你缺了哪些?
  10. 【编译原理】语义分析S属性定义的自下而上计算
  11. android 检查更新 卡住,阴阳师安装更新包卡住怎么办_安装更新包卡住解决办法...
  12. 10M/100M自适应以太网接口
  13. 计算机网络-数据链路层 1
  14. 电脑提示ISDone.dll错误怎么办?
  15. 【附源码】计算机毕业设计SSM实验室预约管理系统
  16. win10快捷键(常用快捷键)
  17. 网络传输中available的用法
  18. 职业素养:如何管理好你的上级
  19. 基于RFID技术的营区车辆管理解决方案-沈阳博能科技
  20. 系统分析与设计-homework1

热门文章

  1. sharpssh远程linux监控系统,利用SharpSsh远程执行linux的shell命令
  2. 让apache解析html里的php代码,让Apache解析html文件中的php语句
  3. opencv对图像是软解码_C ++ OpenCV解码缓慢
  4. python编程 迷你世界_迷你编程下载-迷你世界迷你编程下载 v1.0官方版--pc6下载站...
  5. cxgrid 写数据_大线索报道:2020年策划人必备的50个写方案技巧
  6. 生产调度java程序原码_Rxjava的线程调度源码解析
  7. oracle 换字段顺序,修改ORACLE的字段顺序
  8. C语言fscanf和fprintf函数的用法详解
  9. Struts 2框架创建的第一个项目
  10. JAVA50道经典编程题