使用MyBatis实现第一个web应用
主要目标:在web项目当中使用mybatis1、创建一个web project,我这里使用的servlet版本号是servlet 3.1,
在servlet 3.0版本之后,web.xml文件就可以不写了,所有的配置均采用注解
来完成。2、eclipse部署项目的时候,关于项目的名称:settings目录下的:org.eclipse.wst.common.component<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0"><wb-module deploy-name="mybatis-004"> <!--部署时显示的名称--><wb-resource deploy-path="/" source-path="/WebContent" tag="defaultRootSource"/><wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/><property name="context-root" value="crm"/> <!--项目的真实名称--><property name="java-output-path" value="/mybatis-004/build/classes"/></wb-module></project-modules>3、关于mybatis核心对象的生命周期:SqlSessionFactoryBuilder:这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。String resource = "org/mybatis/example/mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSessionFactorySqlSessionFactory 一旦被创建就应该在应用的运行期间“一直存在”,没有“任何理由”对它进行清除或重建。SqlSessionFactory在整个容器当中只允许出现一个。一个SqlSessionFactory对象,代表了一个数据库,当多数据库开发的时候,SqlSessionFactory对象才会实例化多个。对于单一数据库来说,只能有一个。SqlSession每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。原则:一个线程一个Connection。 (JDBC)一个线程一个SqlSession。(MyBatis)2、步骤:2.1、 导入相关jarlog4j-1.2.17.jarmybatis-3.4.5.jarmysql-connector-java-5.1.23-bin.jar2.2、 引入相关配置文件jdbc.propertieslog4j.propertiesmybatis-config.xmlSqlMapper.xml2.3、数据库表我们就直接使用tbl_student了。tbl_studentid name birth-------------------------------1 zhangsan 1980-11-11...id采用UUID。2.4、准备一个UUID的工具类。2.5、提供一个mybatis的工具类:SqlSessionUtilSqlSession需要放到ThreadLocal当中,必须保证一个线程一个SqlSession对象。2.6、动态代理(JDK动态代理,实现事务的自动管理。)事务在service层控制,所以以后我们不能直接调用service,需要先创建一个service对象的代理对象,通过代理对象执行service当中的方法。2.7、准备前端页面save.jsp准备form表单2.8、web.xml文件的编写,但是我们项目中没有web.xml文件。使用注解。2.9、新建MVC所需要的packagedomaincontrollerservice.impldao.impl2.10、提供StudentController、StudentService、StudentDao2.11、SqlMapper.xml文件一般和dao接口放一块,并且该xml文件的名称一般和dao接口名称一致。不是必须的,只是开发规范。2.12、在mybatis核心文件中配置SqlMapper.xml文件的路径。<mappers><mapper resource="com/wkcto/crm/dao/StudentDao.xml"/></mappers>2.13、在sqlmapper.xml文件中,编写sql语句:<insert id="saveStu" parameterType="com.wkcto.crm.domain.Student">insert into tbl_student(id,name,birth)values(#{id},#{name},#{birth})</insert>--------------------------------------------------------------------------------------<!-- 别名 --><typeAliases><typeAlias type="com.wkcto.crm.domain.Student" alias="Student"/></typeAliases>
package com.wkcto.crm.utils;import java.io.IOException;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;/*** mybatis的工具类。* @author Administrator**/
public class SqlSessionUtil {private static SqlSessionFactory factory;private static ThreadLocal<SqlSession> local = new ThreadLocal<>();/*** 类加载的时候执行,创建一个SqlSessionFactory对象。*/static{try {factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));} catch (IOException e) {e.printStackTrace();}}/*** 获取当前线程中的SqlSession对象* @return*/public static SqlSession getCurrentSqlSession(){// 先从当前线程中取SqlSession对象SqlSession sqlSession = local.get();if(sqlSession == null){ // 从当前线程中没有取到SqlSession对象sqlSession = factory.openSession(); // 获取新的SqlSession对象local.set(sqlSession); // 将SqlSession对象绑定到当前线程中。}return sqlSession;}/*** * @param sqlSession*/public static void rollback(SqlSession sqlSession){if(sqlSession != null){sqlSession.rollback(); }}/*** * @param sqlSession*/public static void close(SqlSession sqlSession){if(sqlSession != null){sqlSession.close();local.remove(); // 记得这行代码(SqlSession对象和当前线程解除绑定)}}
}
package com.wkcto.crm.utils;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;import org.apache.ibatis.session.SqlSession;public class TransactionHandler implements InvocationHandler {private Object target; // 真正的service对象(目标对象)public TransactionHandler(Object target) {this.target = target;}/*** 专门用来获取代理对象的。* @return*/public Object getProxy(){return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {SqlSession sqlSession = null;Object retValue = null;try {sqlSession = SqlSessionUtil.getCurrentSqlSession(); // 开启事务// 真正调用serviceretValue = method.invoke(target, args);sqlSession.commit(); // 提交事务} catch (Exception e) {SqlSessionUtil.rollback(sqlSession);e.printStackTrace();} finally{SqlSessionUtil.close(sqlSession);}return retValue;}}
package com.wkcto.crm.utils;import java.util.UUID;/*** UUID生成器* @author Administrator**/
public class UUIDGenerator { // ....tor ....器,例如:Comparator:比较器// UUIDGenerator采用名词,表示UUID生成器private UUIDGenerator(){}// generate动词:表示生成public static String generate(){return UUID.randomUUID().toString().replaceAll("-", "");}}
domain包
package com.wkcto.crm.domain;public class Student {private String id;private String name;private String birth;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getBirth() {return birth;}public void setBirth(String birth) {this.birth = birth;}}
controller包
package com.wkcto.crm.web.controller;import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import com.wkcto.crm.domain.Student;
import com.wkcto.crm.service.StudentService;
import com.wkcto.crm.service.impl.StudentServiceImpl;
import com.wkcto.crm.utils.TransactionHandler;
import com.wkcto.crm.utils.UUIDGenerator;// @WebFilter
// @WebListener@WebServlet(urlPatterns={"/student/save.do"})
public class StudentController extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doPost(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 接收表单参数String id = UUIDGenerator.generate();String name = request.getParameter("name");String birth = request.getParameter("birth");Student s = new Student();s.setId(id);s.setName(name);s.setBirth(birth);// 获取service代理对象// 不能这样:StudentService studentService = new StudentServiceImpl(); //这样事务失效了。StudentService studentService = (StudentService)new TransactionHandler(new StudentServiceImpl()).getProxy(); // 调用代理方法boolean ok = studentService.save(s);// 响应JSONresponse.getWriter().print("{\"success\" : "+ok+"}");}
}
service包
package com.wkcto.crm.service;import com.wkcto.crm.domain.Student;public interface StudentService {/*** 保存学生* @param s* @return*/boolean save(Student s);}
serviceimpl包
package com.wkcto.crm.service.impl;import com.wkcto.crm.dao.StudentDao;
import com.wkcto.crm.dao.impl.StudentDaoImpl;
import com.wkcto.crm.domain.Student;
import com.wkcto.crm.service.StudentService;public class StudentServiceImpl implements StudentService {private StudentDao studentDao = new StudentDaoImpl(); @Overridepublic boolean save(Student s) {return studentDao.save(s) == 1;}}
dao包
package com.wkcto.crm.dao;import com.wkcto.crm.domain.Student;public interface StudentDao {/*** 保存学生* @param s* @return 1表示成功,其他值表示失败*/int save(Student s);}
daoImpl
package com.wkcto.crm.dao.impl;import com.wkcto.crm.dao.StudentDao;
import com.wkcto.crm.domain.Student;
import com.wkcto.crm.utils.SqlSessionUtil;public class StudentDaoImpl implements StudentDao {@Overridepublic int save(Student s) {return SqlSessionUtil.getCurrentSqlSession().insert("saveStu", s);}}
sql配置文件
<?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="fdsjkafldjkslafds"><insert id="saveStu" parameterType="Student">insert into tbl_student(id,name,birth)values(#{id},#{name},#{birth})</insert></mapper>