通过自动回复机器人学Mybatis基础(一)---慕课网

1.案例简介

以微信公众号为例,用户回复XXX会推送更精彩的内容,还有运营商的短信回复功能XXX,单纯功能本身并不复杂,这里我们把用户发送的内容当做指令,根据指令来自动回复对应的内容,我们就通过这个小案例实战开发来学习mybatis。
这里我们需要掌握的知识,jsp页面,用jstl来做逻辑控制和页面上值的展示,同时要配合EL表达式,脚本是JS或者JQUERY,后台的控制跳转servlet包括一些逻辑,javabean我们也是少不了的。持久层我们先暂时不用mybatis,先用一个最经典的JDBC来实现,数据库用mysql,先用这样的模式快速的完成一个模块的开发,然后等开发完成之后我们再把JDBC替换成mybatis。
基本功能:

  • 接收发送指令
  • 根据指令自动回复对应的内容

模块划分:

  • 对话功能
  • 回复内容维护,增删改查,回复内容列表显示

接下来我们就用Jsp+Servlet+Jdbc来实现我们最基础的模块。

2.页面跳转

这里我们创建一个servlet,ListTwoServlet,index.jsp访问请求会发送给ListTwoServlet,然后其跳转到页面List.jsp。功能本身简单,但由于之前学的忘了很多,所以还是遇到了一些问题。
主要问题是关于servlet的web.xml文件映射配置弄不好,各种报错,还有就是要及时将对应的jar包放在它该有的位置。index.jsp页面的跳转,注意web.xml配置时映射的url-pattern属性,这里超链接跳转我们使用相对地址。
index.jsp
<a href="ListTwoServlet">测试超链接</a>
web.xml配置,这里只显示了映射的配置内容

<servlet-class>ListTwoServlet</servlet-class> 
<url-pattern>/ListTwoServlet</url-pattern>

如果用注解@WebServlet可以不web.xml直接使用,注解@webServlet如下

@WebServlet(name="/ListTwoServlet",urlPatterns="/ListTwoServlet")

或者

@WebServlet("/ListTwoServlet")

Servlet的跳转

request.getRequestDispatcher("/WEB-INF/jsp/back/List.jsp").forward(request, response);

3.设置List.jsp页面

最终转向的页面是我们的List.jsp。这里先从课程那里下一个jsp的模板,然后开始调整。
List.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible"content="IE=9; IE=8; IE=7; IE=EDGE" />
<title>内容列表页面</title>
<link href="css/all.css" rel="stylesheet" type="text/css" />
</head>
<body style="background: #e1e9eb;">
<form action="" id="mainForm" method="post">
			<div class="right">
				<div class="current">当前位置:<a href="javascript:void(0)" style="color:#6E6E6E;">内容管理</a> &gt; 内容列表</div>
				<div class="rightCont">
					<p class="g_title fix">内容列表 <a class="btn03" href="#">新 增</a>&nbsp;&nbsp;&nbsp;&nbsp;<a class="btn03" href="#">删 除</a></p>
					<table class="tab1">
						<tbody>
							<tr>
								<td width="90" align="right">演示字段1:</td>
								<td>
									<input type="text" class="allInput" value=""/>
								</td>
								<td width="90" align="right">演示字段2:</td>
								<td>
									<input type="text" class="allInput" value=""/>
								</td>
	                            <td width="85" align="right"><input type="submit" class="tabSub" value="查 询" /></td>
	       					</tr>
						</tbody>
					</table>
					<div class="zixun fix">
						<table class="tab2" width="100%">
							<tbody>
								<tr>
								    <th><input type="checkbox" id="all" onclick="#"/></th>
								    <th>序号</th>
								    <th>演示字段1</th>
								    <th>演示字段2</th>
								    <th>操作</th>
								</tr>
								<tr>
									<td><input type="checkbox" /></td>
									<td>1</td>
									<td>演示值1</td>
									<td>演示值2</td>
									<td>
										<a href="#">修改</a>&nbsp;&nbsp;&nbsp;
										<a href="#">删除</a>
									</td>
								</tr>
								<tr style="background-color:#ECF6EE;">
									<td><input type="checkbox" /></td>
									<td>2</td>
									<td>演示值1</td>
									<td>演示值2</td>
									<td>
										<a href="#">修改</a>&nbsp;&nbsp;&nbsp;
										<a href="#">删除</a>
									</td>
								</tr>
								<tr>
									<td><input type="checkbox" /></td>
									<td>3</td>
									<td>演示值1</td>
									<td>演示值2</td>
									<td>
										<a href="#">修改</a>&nbsp;&nbsp;&nbsp;
										<a href="#">删除</a>
									</td>
								</tr>
								<tr style="background-color:#ECF6EE;">
									<td><input type="checkbox" /></td>
									<td>4</td>
									<td>演示值1</td>
									<td>演示值2</td>
									<td>
										<a href="#">修改</a>&nbsp;&nbsp;&nbsp;
										<a href="#">删除</a>
									</td>
								</tr>
							</tbody>
						</table>
						<div class='page fix'>
							共 <b>4</b> 条
							<a href='###' class='first'>首页</a>
							<a href='###' class='pre'>上一页</a>
							当前第<span>1/1</span>页
							<a href='###' class='next'>下一页</a>
							<a href='###' class='last'>末页</a>
							跳至&nbsp;<input type='text' value='1' class='allInput w28' />&nbsp;页&nbsp;
							<a href='###' class='go'>GO</a>
						</div>
					</div>
				</div>
			</div>
	    </form>
</body>
</html>

这里我们先仔细看一遍这个jsp,再进行下一步。因为之前这里遗忘的太多,所以慢慢做一个补充复习。
background 背景;form action 提交,表单会自动提交到括号中的内容;div 是一个块级元素,也就是说,浏览器通常会在 div 元素前后放置一个换行符。可以对同一个div元素应用 class 或 id 属性,但是更常见的情况是只应用其中一种。这两者的主要差异是,class 用于元素组(类似的元素,或者可以理解为某一类元素),而 id 用于标识单独的唯一的元素;a href="#"是一种临时链接的写法,这样写就是说这个链接目前不可用,点击了也不会有作用,还是会跳转到本页,当#被有效链接替换才会起作用的,一般建议写成javascript:void(0);要好一点,点了一点反应都没有,写#点了可能会跳一下。
这里还遇到的问题是关于css文件不起作用,原因是将css文件放到了web-inf目录下,这样没法访问所以引用也是失效的。在根目录下创建resources文件夹将图片和css都放进其中不同的文件夹,这里写相对路径CSS引用就起作用了。

<link type="text/css" rel="stylesheet" href="resources/css/all.css" />

在HTML里我们用这种方式引用css就是可以的,但是在jsp里用这个就显得不专业,这时就用到下面这种访问方式。

<% String path=request.getContextPath(); 
   String NicePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/"+path+"/";
%>    

这个很好的写出了怎么访问工程的根目录path以及url方式。

4.数据库的连接

这里数据库的连接还是用我们JDBC的方式,首先将数据表中的数据存入数据库中,这里我们创建了数据库imooc,并在其中添加表message。这里我们会从servlet里直接实现jdbc对数据库的访问。
这里出现了报错,在JDBC使用的时候有时候会出现

java.sql.SQLException: The server time zone value '???ú±ê×??±??' is unrecognized or represents........

的错误,出现这个的原因是因为 mysql返回的时间总是有问题,比实际时间要早8小时。在jdbc连接的url后面加上serverTimezone=GMT即可解决问题,如果需要使用gmt+8时区,需要写成GMT%2B8,问题就会解决;

Connection conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/imooc?useSSL=false&serverTimezone=GMT","root","123456789");

同时还遇到一个问题是说我driver的名称写错了,这里就要提到

com.mysql.cj.jdbc.Driver  是 mysql-connector-java 6中的
com.mysql.jdbc.Driver 是 mysql-connector-java 5中的

之间的区别。这里正确写法是加了cj的,同时因为是这样的写法就需要设置时区serverTimezone。如果mysql-connector-java用的6.0以上的,但是你的driver用的还是com.mysql.jdbc.Driver,就会报错,此时需要把com.mysql.jdbc.Driver 改为com.mysql.cj.jdbc.Driver。

这里我们需要建立一个javabean实体类来对应数据库中的数据,建立一个类Message,它的四个属性值分别对应数据库中的属性,建立getset方法。因为已经连接好了数据库,所以要查询里面的内容,将之放在一个list列表中,属性一一对应。

try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			Connection conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/imooc?useSSL=false&serverTimezone=GMT","root","123456789");
			Statement stmt=conn.createStatement();
			ResultSet rs=stmt.executeQuery("SELECT ID,COMMAND,DESCRIPTION,CONTENT FROM message");//sql语句不能写星
			List<Message> messageList=new ArrayList<Message>();
			while(rs.next()){
					Message message=new Message();
					message.setId(rs.getString("ID"));
					message.setCommand(rs.getString("COMMAND"));
					message.setDescription(rs.getString("DESCRIPTION"));
					message.setContent(rs.getString("CONTENT"));
					messageList.add(message);
					
	            }
	            request.setAttribute("messageList", messageList);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

这里注意查询属性时不能写星号,要每个属性都写出来。这里我们就获取了一个Message的list。并且将它添加到请求的属性当中messageList。

5.List.jsp页面值的展示

List.jsp 这就是我们最终要跳转的JSP页面,效果则是类似后台会有一个表格,将数据库中的信息显示出来。上面我们已经弄好了一个基础,下面开始正式的补充一下,好将数据库中的内容显示出来,这里我们需要复习一下EL表达式。
要使用jstl首先要

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
 
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>   
<% String path=request.getContextPath(); 
   String NicePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+"/"+path+"/";
%>    
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<meta http-equiv="X-UA-Compatible"content="IE=9; IE=8; IE=7; IE=EDGE" />
		<title>内容列表页面</title>
		<link href="<%=NicePath %>all.css" rel="stylesheet" type="text/css" />
	</head>
	<body style="background: #e1e9eb;">
		<form action="" id="mainForm" method="post">
			<div class="right">
				<div class="current">当前位置:<a href="javascript:void(0)" style="color:#6E6E6E;">内容管理</a> &gt; 内容列表</div>
				<div class="rightCont">
					<p class="g_title fix">内容列表 <a class="btn03" href="#">新 增</a>&nbsp;&nbsp;&nbsp;&nbsp;<a class="btn03" href="#">删 除</a></p>
					<table class="tab1">
						<tbody>
							<tr>
								<td width="90" align="right">演示字段1:</td>
								<td>
									<input type="text" class="allInput" value=""/>
								</td>
								<td width="90" align="right">演示字段2:</td>
								<td>
									<input type="text" class="allInput" value=""/>
								</td>
	                            <td width="85" align="right"><input type="submit" class="tabSub" value="查 询" /></td>
	       					</tr>
						</tbody>
					</table>
					<div class="zixun fix">
						<table class="tab2" width="100%">
							<tbody>
								<tr>
								    <th><input type="checkbox" id="all" onclick="#"/></th>
								    <th>序号</th>
								    <th>指令名称</th>
								    <th>描述</th>
								    <th>操作</th>
								</tr>
								<c:forEach items="${al}" var="al" varStatus="status">
								
								
								<tr <c:if test="${status.index%2!=0}">style="background-color:#ECF6EE;"</c:if> >
									<td><input type="checkbox" /></td>
									<td>${status.index+1}</td>
									<td>${al.COMMAND }</td>
									<td>${al.DESCRIPTION}</td>
									
									<td>
										<a href="#">修改</a>&nbsp;&nbsp;&nbsp;
										<a href="#">删除</a>
									</td>
								</tr>
								</c:forEach>
								
							</tbody>
						</table>
						<div class='page fix'>
							共 <b>4</b> 条
							<a href='###' class='first'>首页</a>
							<a href='###' class='pre'>上一页</a>
							当前第<span>1/1</span>页
							<a href='###' class='next'>下一页</a>
							<a href='###' class='last'>末页</a>
							跳至&nbsp;<input type='text' value='1' class='allInput w28' />&nbsp;页&nbsp;
							<a href='###' class='go'>GO</a>
						</div>
					</div>
				</div>
			</div>
	    </form>
	</body>
</html>

AppServlet,负责中间跳转

@SuppressWarnings("serial")
@WebServlet(name="/AppServlet",urlPatterns="/servlet/AppServlet")
public class AppServlet extends HttpServlet  {
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		try {
			
			Class.forName("com.mysql.jdbc.Driver");
			Connection coon= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/imooc","root","123456789");
			String sql="select ID,COMMAND,DESCRIPTION,CONTENT FROM message;";
			PreparedStatement statement=coon.prepareStatement(sql);
			ResultSet rs=statement.executeQuery();
			ArrayList<Message> al=new ArrayList<Message>();
			
			while(rs.next()) {
				Message m=new Message();
				m.setID(rs.getInt("ID"));
				m.setCOMMAND(rs.getString("COMMAND"));
				m.setCONTENT(rs.getString("CONTENT"));
				m.setDESCRIPTION(rs.getString("DESCRIPTION"));
				al.add(m);
				
			}
			req.setAttribute("al", al);
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		req.getRequestDispatcher("/WEB-INF/lib/JSP/Demo01.jsp").forward(req, resp);
		
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		this.doGet(req, resp);
	}
}

Web.xml

 <!--<servlet>
  	<servlet-name>AppServlet</servlet-name>
  	<servlet-class>AppServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>AppServlet</servlet-name>
  	<url-pattern>/servlet/AppServlet</url-pattern>
  </servlet-mapping>
    -->

这里还有一个对应的实体类以及css文件就不写了。
关于数据库连接及展示,这个实现已经在上面的例子里了,通过JDBC以及一个jstl循环el表达式来显示在页面中。

3.列表查询

这里通过拼接sql语句来查询,并且加上判断语句,如果存在值则可以拼接。
修改jsp这种的值

<form action="AppServlet" id="mainForm" method="post">
				<div class="right">
					<div class="current">当前位置:<a href="javascript:void(0)" style="color:#6E6E6E;">内容管理</a> &gt; 内容列表</div>
					<div class="rightCont">
						<p class="g_title fix">内容列表 <a class="btn03" href="#">新 增</a>&nbsp;&nbsp;&nbsp;&nbsp;<a class="btn03" href="#">删 除</a></p>
						<table class="tab1">
							<tbody>
								<tr>
									<td width="90" align="right">指令名称:</td>
									<td>
										<input name="command" type="text" class="allInput" value="${command}"/>
									</td>
									<td width="90" align="right">描述:</td>
									<td>
										<input name="description" type="text" class="allInput" value="${description}"/>
									</td>
		                            <td width="85" align="right"><input type="submit" class="tabSub" value="查 询" /></td>
		       					</tr>
							</tbody>
						</table>
						<div class="zixun fix">
							<table class="tab2" width="100%">
								<tbody>
									<tr>
									    <th><input type="checkbox" id="all" onclick="#"/></th>
									    <th>序号</th>
									    <th>指令名称</th>
									    <th>描述</th>
									    <th>操作</th>
									</tr>
									<c:forEach items="${al}" var="al" varStatus="status">
									
									
									<tr <c:if test="${status.index%2!=0}">style="background-color:#ECF6EE;"</c:if> >
										<td><input type="checkbox" /></td>
										<td>${status.index+1}</td>
										<td>${al.COMMAND }</td>
										<td>${al.DESCRIPTION}</td>
										
										<td>
											<a href="#">修改</a>&nbsp;&nbsp;&nbsp;
											<a href="#">删除</a>
										</td>
									</tr>
									</c:forEach>
									
								</tbody>
							</table>
							<div class='page fix'>
								共 <b>4</b> 条
								<a href='###' class='first'>首页</a>
								<a href='###' class='pre'>上一页</a>
								当前第<span>1/1</span>页
								<a href='###' class='next'>下一页</a>
								<a href='###' class='last'>末页</a>
								跳至&nbsp;<input type='text' value='1' class='allInput w28' />&nbsp;页&nbsp;
								<a href='###' class='go'>GO</a>
							</div>
						</div>
					</div>
				</div>
		    </form>

修改servlet doget方法

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		req.setCharacterEncoding("utf-8");
		try {
			String command=req.getParameter("command");
			String description=req.getParameter("description");
			req.setAttribute("command", command);
			req.setAttribute("description", description);
			Class.forName("com.mysql.jdbc.Driver");
			Connection coon= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/imooc","root","123456789");
			StringBuilder sql=new StringBuilder("select ID,COMMAND,DESCRIPTION,CONTENT FROM message where 1=1");
			List<String> paramList=new ArrayList<String>();
			if(command!=null&&!"".equals(command.trim())) {
				sql.append(" and COMMAND=?");
				paramList.add(command);
			}
			if(description!=null&&!"".equals(description.trim())) {
				sql.append(" and DESCRIPTION like '%' ? '%'");
				paramList.add(description);
			}
			
			PreparedStatement statement=coon.prepareStatement(sql.toString());
			for(int i=0;i<paramList.size();i++) {
				statement.setString(i+1, paramList.get(i));
			}
			
			
			ResultSet rs=statement.executeQuery();
			ArrayList<Message> al=new ArrayList<Message>();
			
			while(rs.next()) {
				Message m=new Message();
				m.setID(rs.getInt("ID"));
				m.setCOMMAND(rs.getString("COMMAND"));
				m.setCONTENT(rs.getString("CONTENT"));
				m.setDESCRIPTION(rs.getString("DESCRIPTION"));
				al.add(m);
				
			}
			req.setAttribute("al", al);
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		req.getRequestDispatcher("/WEB-INF/lib/JSP/Demo01.jsp").forward(req, resp);
		
	}

4.代码重构

仔细看上面的代码,没有注释,繁复且都在servlet的一个方法里。
这里添加注释并且将jdbc和返回消息拆分成一个dao层和service。dao层写一个方法,根据查询条件查询消息列表,service包中添加一个类,将查询的结果返回给servlet。

5.Mybatis 的下载并搭建核心架构

这里首先下载mybatis的jar包,以及源码的包,配置文件需要利用这个xml文件
mybatis-3-mybatis-3.4.5\src\test\java\org\apache\ibatis\submitted\complex_property\configuration.xml
配置的时候我们首先把jdbc的内容替换掉,dao层操作数据库,不需要jdbc的连接。dao层的需求是对象能与数据库交互,能执行sql语句。那么mybatis是如何向dao层提供这个对象的,提供的这个对象又叫什么。这个对象叫sqlSession,这个是mybatis最最核心的一个对象,为什么这个对象有这么重要。我们看下sqlSession到底有什么作用。
SqlSession作用:

  • 向sql语句传入参数。之前我们在执行预编译的sql语句,那就必须得要通过一个对象为这个去设置这些预编译的参数
  • 执行sql语句
  • 获取执行sql语句的结果
  • 事务的控制

如何得到sqlSession:

  • 通过配置文件获取数据库连接相关信息
  • 通过配置信息构建sqlSessionFactory
  • 通过sqlSessionFactory打开一个数据库会话

dao包

public class MessageDao {
	/**
	 * 根据查询条件查询消息列表 
	 */
	public List<Message> queryMessageList(String command,String description) {
		DBAccess dbaccess=new DBAccess();
		SqlSession sqlSession=null;
		try {
			sqlSession=dbaccess.getSqlSession();
			//通过sqlSession执行sql语句
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			if(sqlSession!=null) {
				sqlSession.close();
			}
		}
		
	
	return null;
	}
	}

db

/**
 * 访问数据库类
 * @author Administrator
 *
 */
public class DBAccess {
	public SqlSession getSqlSession() throws IOException {
		//通过配置文件获取数据库连接信息,这里注意不要trycatch而是throw给dao层去处理
		//同时要注意之前jdbc我们没有写全,好些没有关闭操作,这里都要补充好。mybatis是jdbc的二次封装
		Reader reader=Resources.getResourceAsReader("config/Configuration.xml");
		//通过配置信息构建一个SqlSessionFactory
		SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
		//通过sqlSessionFactory去打开一个数据库会话
		SqlSession sqlSession=sqlSessionFactory.openSession();
		return sqlSession;
	}
}

configuration.xml

<environments default="development">
    <environment id="development">
      <transactionManager type="JDBC">
        <property name="" value=""/>
      </transactionManager>
      <dataSource type="UNPOOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/imooc"/>
        <property name="username" value="root"/>
        <property name="password" value="123456789"/>
      </dataSource>
    </environment>
  </environments>

这里上面只是获取了一个连接执行sql语句,接下来就要对sql进行配置

6.SQL 基本配置与执行

mybatis不像jdbc是把sql语句锁死执行的,也不是像之前写的用动态拼接去执行。mybatis大部分的工作是在配置文件里,sql语句也少不掉,写在配置文件里。之前我们从官方演示代码里copy过来一个核心配置文件,同目录里还有一个user.xml,它就是我们的sql配置演示
user.xml要改名 这里改成使用的那个库的名字,方便一点 Message.xml,resultMap这个节点是用来对应数据库的字段和我们的实体类的属性,有了它当我们查询到了信息就会自动赋值到对应的字段,mapper namespace="Message"这个字段的这个命名在我们实际调用查询的时候会需要用到SqlSession.select(“Message.方法对应id”),这样使用,select节点的id就是唯一id用来区分不同的sql语句,而后面的resultMap对应的就是我们刚刚说的resultMap字段,输入即可。注意这个完成后还需要在configuration.xml里配置,也就是我们的核心xml文件。

<?xml version="1.0" encoding="UTF-8"?>
<!--

       Copyright 2009-2016 the original author or authors.

       Licensed under the Apache License, Version 2.0 (the "License");
       you may not use this file except in compliance with the License.
       You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

       Unless required by applicable law or agreed to in writing, software
       distributed under the License is distributed on an "AS IS" BASIS,
       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       See the License for the specific language governing permissions and
       limitations under the License.

-->
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="Message">

  <resultMap type="Message" id="MessageResult">
    <id column="ID" jdbcType="INTEGER" property="ID"/>
    <result column="COMMAND" jdbcType="VARCHAR" property="COMMAND"/>
    <result column="CONTENT" jdbcType="VARCHAR" property="CONTENT"/>
    <result column="DESCRIPTION" jdbcType="VARCHAR" property="DESCRIPTION"/>
  </resultMap>

  <select id="queryMessageList" resultMap="MessageResult">
    select ID,COMMAND,DESCRIPTION,CONTENT FROM message where 1=1
  </select>

</mapper>

configuration.xml

<!--这个节点可以是多个-->
  <mappers>
    <mapper resource="Message.xml"/>
  </mappers>

MessageDao

public List<Message> queryMessageList(String command,String description) {
		List<Message> al=new ArrayList<Message>();
		DBAccess dbaccess=new DBAccess();
		SqlSession sqlSession=null;
		try {
			sqlSession=dbaccess.getSqlSession();
			//通过sqlSession执行sql语句
			al=sqlSession.selectList("Message.queryMessageList");
			
			
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally {
			if(sqlSession!=null) {
				sqlSession.close();
			}
		}
		
	
	return al;
	}

7.动态 SQL 拼接

我们来接着完善这个查询功能,这里传参修改,在接收了参数之后,配置文件又怎么去接收这个参数呢?

al=sqlSession.selectList("Message.queryMessageList",command,description);

这是dao层方法体的参数就是command和description,在执行sql语句上将这两个参数传递进去,在Message.xml该如何处理呢?这里需要用到parameterType属性,这个属性里不需要写变量名,只需要些类型,这时是不是该

 <select id="queryMessageList" parameterType="String,String" resultMap="MessageResult">
    select ID,COMMAND,DESCRIPTION,CONTENT FROM message where 1=1
  </select>

这样是不对的,这个属性只能添加一个,这也是为啥上面的参数添加以后会报错。只能传递一个变量,此时我们就可以加参数封装成一个对象就可以了,在message这个实体类里正好有这两个属性,这样直接传递一个Message的对象就可以了,并且将变量添加到这个对象的属性中去。由此得出结果

//dao层
Message mm=new Message(command,description);
		try {
			sqlSession=dbaccess.getSqlSession();
			//通过sqlSession执行sql语句
			al=sqlSession.selectList("Message.queryMessageList",mm);
			}

message.xml配置层
 <select id="queryMessageList" parameterType="Message" resultMap="MessageResult">
    select ID,COMMAND,DESCRIPTION,CONTENT FROM message where 1=1
  </select>

这里要注意parameterType的值有时候需要把地址写全。若lang包下的String,这种不需要,这里我没有添加一样可以使用,接下来就是拼接的工作了,我们来看之前写的java语句,是通过if语句对参数进行判断来决定是否继续为这条语句在后面进行拼接。那在配置文件里怎么去表达呢?
尽管不能像java语句中直接使用if,但是可以使用if标签,

<select id="queryMessageList" parameterType="Message" resultMap="MessageResult">
    select ID,COMMAND,DESCRIPTION,CONTENT FROM message where 1=1
	<if test=""> and COMMAND=?</if>  
</select>

这里的test标签中的表达式如果成立,则在后面拼接内容。 此时是在.xml文件中,虽然if标签跟之前的差不多,但是不能使用el表达式,此时就要使用OGNL表达式,OGNL与EL一样,是一种语言,用EL写出来的是EL表达式,用OGNL写出来的就是OGNL表达式,这个不是mybatis专有的,它是独立的,很多地方都会用到,比如struts2。OGNL在mybatis中有它自己的特色,这里只总结mybatis中的OGNL。

OGNL表达式标签的属性
String与其他基本数据类型_parameter
自定义类型(如Message)属性名(如command)
集合-数组array
集合-Listlist
集合-Map_parameter
从数组中取一条数据(例String数组)array[索引](String[])
从自定义数组中取一条数据(例Message数组)array[索引].属性名(Message[])
从List中取一条数据(例String)list[索引](List<String>
从自定义List中取一条数据(例Message)list[索引].属性(List<Message>
从Map中取一条数据_parameter.key(Map<String,String>)
从Map中取一条数据key(Map<String,Message>) _parameter可以省略
不知索引时可用foreach标签从集合中取数据<foreach collection="array" index="i" item="item">
foreach——数组i:搜索下标,item就是item,如果是自定义对象则item.属性
foreach——Listi:搜索下标,item就是item,如果是自定义对象则item.属性
foreach——Mapi:key值,item就是item,如果是自定义对象则item.属性
操作符——java常用+ - * / == || &&等等
操作符——自己特有的操作符and or mod取余 in(判断值是否在一个集合中) not in

这里我们看之前的条件if(command!=null&&!"".equals(command.trim()))java符号是可以用的,但是第二个条件,我们知道OGNL是一个功能强大的表达式语言,它有一个非常重要的功能,不光能从java的对象中去取属性值,而且他能直接调用java对象的方法,所以直接复制粘贴就是可以用的,空字符串是一个对象,command也是字符串。这里发现还是报错
<if test="COMMAND!=null && !"".equals(COMMAND.trim())">
是因为xml中双引号和外面的双引号冲突了,需要转义,同时&&这个也需要转义。

<if test="COMMAND!=null &amp;&amp; !&quot;&quot;.equals(COMMAND.trim())"> and COMMAND=?</if>  
&amp;代表&,&quot;代表;

或者用OGNL自己的操作符 and ,直接写and也可以,现在还剩下一个问题?,配接的这个?该怎么处理,mybatis对于这个有自己特殊的写法,他不是直接写问号,写?的话mybatis没办法为你赋值,她也不知道用什么值来填充这个问号。这里是用#{COMMAND},这里注意他只是取值写法和OGNL一样,但是它不具备OGNL其他特性,这个地方他不是OGNL,当它解析时遇到#{}的时候,它会将你把这个地方替换成问号,然后在替换之前它知道你里面写的变量名,他也知道是从哪一个范围里面去取,他就能做你原来JDBC里的填充操作了。

 <select id="queryMessageList" parameterType="Message" resultMap="MessageResult">
    select ID,COMMAND,DESCRIPTION,CONTENT FROM message where 1=1
	<if test="COMMAND!=null &amp;&amp; !&quot;&quot;.equals(COMMAND.trim())"> and COMMAND=#{COMMAND}</if>  
  	<if test="DESCRIPTION!=null and !&quot;&quot;.equals(DESCRIPTION.trim())"> and DESCRIPTION like '%' #{DESCRIPTION} '%'</if>  
  </select>

运行测试成功

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值