(7)。mybatis动态查询,collection实现⼀对多的查询where条
件可变的查。。。
resultmap中association实现的是多对⼀的查询(数据库的列对类属性的映射):eg:多个作者对应同⼀个⽂章
resultMap中的collection实现⼀对多的查询                :eg:⼀个⽂章对应多个评论
数据库中常⽤的数据类型:
  int                    <=>          int
  varchar            <=>          String
  datetime          <=>          Date
collection本⾝是集合
⼀。collection的相关知识:
<resultMap id="newsResultMapComplex" type="com.bean.News">
<result property="id" column="id"/>
<result property="title" column="title"/>
<result property="content" column="content"/>
<result property="keywords" column="keywords"/>
<result property="pubtime" column="pubtime"/>
<result property="usersId" column="users_id"/>
<result property="checkUsersId" column="check_users_id"/>
<result property="categoryId" column="category_id"/>
<result property="checkUsersName" column="checkUsersName"/>
<result property="categoryName" column="categoryName"/>
<association property="owner" javaType="com.bean.Users">
<result property="id" column="u_id"/>
<result property="nickname" column="nickname"/>
<result property="realname" column="realname"/>
<result property="phone" column="phone"/>
<result property="email" column="email"/>
<result property="address" column="address"/>
<result property="createTime" column="u_create_time"/>
</association>
<collection property="replys" ofType="com.bean.Replys">
<result property="id" column="r_id"/>
<result property="newsId" column="r_news_id"/>
<result property="content" column="r_content"/>
<result property="usersId" column="r_users_id"/>
<result property="replysId" column="r_replys_id"/>
<result property="createTime" column="r_create_time"/>
</collection>
</resultMap>
对于u.id u_id这种,u_id表⽰的是重命名,并且在resultmap中的column也需要反复更改。(重命名的需要更改)property代表的是类⾥的属性
以下代码实现的⽬的:是以新闻为主题,查询新闻的作者(类)⾥信息和分类信息(等值连接),然后与回复进⾏左连接,之后以新闻id主查询它的回复的前两名。
<select id="findNewsWithReplyss" resultMap="newsResultMapComplex"
parameterType="int">
select
n.id,
n.title,
n.users_id,
n.category_id,
n.pubtime,
n.keywords,
n.state,
n.check_users_id,
n.check_time checkTime,
n.is_elite isElite,
u.nickname,
mybatis面试题alname,
u.phone,
u.address,
r.id r_id,
r.users_id r_users_id,
c.name categoryName,
u1.nickname checkUsersName
from n_news n inner join n_users u on n.users_id = u.id
inner join n_category c on n.category_id = c.id
inner join n_users u1 on n.check_users_id = u1.id
left join n_replys r ws_id = n.id
where n.id = #{id}
order by r.id desc
limit 0,2
</select>
企业派做法:不要外键,虽真实存在。
当查询很复杂时,resultMap会过于复杂。
于是当过于复杂时,我们不要外键,把复杂的数据库语句拆分。纵向发展,拆分为简单的数据库语句,之后使⽤set⽅法来设置属性。对于过于复杂的查询语句我们建议不⽤association与collection,使⽤简单的数据库语句进⾏查询。
需完善NewsServlet:
package com.web;
import com.bean.Categorys;
import com.bean.News;
import com.dao.CategorysMapper;
import com.dao.NewsMapper;
import com.util.MybatisUtils;
import com.util.StringUtil;
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 java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@WebServlet(urlPatterns = "/news/list",name="NewsServlet")
public class NewsServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String op = Parameter("op");
if("list".equals(op)){
list(req,resp);
}else if("find".equals(op)){
find(req,resp);
}
/*NewsMapper Mapper(NewsMapper.class);
List<News> list=newDao.findAllComplex();
//将查询到的数据库信息存储得到“请求作⽤域”
req.setAttribute("list",list);//前⾯⼀个
}
private void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
NewsMapper Mapper(NewsMapper.class);
List<News> list=newDao.findAllComplex();
//将查询到的数据库信息存储得到“请求作⽤域”
req.setAttribute("list",list);//前⾯⼀个
private void find(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
NewsMapper newsDao = Mapper(NewsMapper.class);
int newsId = Int(req,"id");
News news = newsDao.findNewsWithReplys(newsId);
// 将查询到的数据库信息存储到“请求作⽤域”
req.setAttribute("news", news);
}
}
完善新闻详情界⾯:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="java.sun/jsp/jstl/core" %>
<html>
<head>
<title>新闻内容</title>
</head>
<body>
<p>⾸页/新闻/内容</p>
<h1>${news.title}</h1>
<p>
关键字:<span>${news.keywords}</span>
作者:<span>${news.owner.nickname}</span>
发布时间:<span>${news.pubtimeString}</span>
</p>
<div>
${t}
</div>
<h3>评论</h3>
<hr/>
<div>
<ul>
<c:forEach items="${plys}" var="reply">
<li>${t} - ${ateTimeString}</li>
</c:forEach>
</ul>
</div>
</body>
</html>
⼆。动态查询:where条件可变的查询,即where条件可变。
⽬标:动态查询。
实现⽅法是:可以在mybatis的映射⽂件中使⽤if,choose(when,otherwise),where,set,trim,foearch标签实现动态SQL.
  if:判断
  choose:⼦标签(when,otherwise),⼀般可以被if替换。
  where:专⽤于select查询
  set:专⽤于update处理。
  trim:有替换的功能。
  foearch:⼀般⽤于in的情况下。
背景及需求:假定需要按照新闻分类(category_id)进⾏查询,如果⽤户没有提供分类查询则查询所有的新闻,否则查询指定分类的新闻。
为什么使⽤map类型,⽽不使⽤类类型,是由map类型没有预设,传输需要的值更加⽅便。(此处的参数也有可能会被换为更加合适:查询bean)
<!--java.util.Map,映射,键值对。为啥不⽤News类?
pubtime:pubtime>='2020-03-20'、pubtime<='2020-03-25'
bean:实体bean、业务bean、查询bean
-->
<select id="find" resultMap="newsResultMapComplex"
parameterType="map">
concat(substring(n.title,1,8),if(char_length(n.title)>8,'...','')) title,
concat(t,1,8),if(char_t)>8,'...','')) content,
n.users_id,
n.category_id,
n.pubtime,
n.keywords,
n.state,
n.check_users_id,
n.check_time checkTime,
n.is_elite isElite,
u.id u_id,
u.nickname,
u.phone,
u.address,
c.name categoryName,
u1.nickname checkUsersName
from n_news n inner join n_users u on n.users_id = u.id
inner join n_category c on n.category_id = c.id
inner join n_users u1 on n.check_users_id = u1.id
<where>
<if test="keywords != null">
and keywords like concat('%',#{keywords},'%')
</if>
<if test="category_id != null">
and category_id = #{category_id}
</if>
<if test="startTime != null">
and n.pubtime >= #{startTime}
</if>
<if test="endTime != null">
and n.pubtime <= #{endTime}
</if>
<if test="title != null im().length() > 0">
and n.title = #{title}
</if>
</where>
order by n.id desc
</select>
多条件查询的
第⼀种⽅法如上,把if标签放在where标签内,mybatis特有的,并且要求把if标签括在where中。第⼆种⽅法:添加⼀个⼀定实现的条件,把sql语句进⾏拼装。
from n_news n inner join n_users u on n.users_id = u.id
inner join n_category c on n.category_id = c.id
inner join n_users u1 on n.check_users_id = u1.id
where 1=1
<if test="keywords != null">
and keywords like concat('%',#{keywords},'%')
</if>
<if test="category_id != null">
and category_id = #{category_id}
</if>
<if test="startTime != null">
and n.pubtime >= #{startTime}
</if>
<if test="endTime != null">
and n.pubtime <= #{endTime}
</if>
<if test="title != null im().length() > 0">
and n.title = #{title}
</if>
2.添加⽅法:
List<News> find(Map<String, Object> params);
3.单元测试
public void find(){
NewsMapper Mapper(NewsMapper.class);
Map<String ,Object> params=new HashMap<>();
List<News> result=dao.find(params);
Assert.assertEquals(3,result.size());
params.put("keywords","java");
result=dao.find(params);
Assert.assertEquals(2,result.size());
params.put("category_id","1");
result=dao.find(params);
Assert.assertEquals(1,result.size());
//      params.put("category_id",1);
//        result = dao.find(params);
//        Assert.assertEquals(2,result.size());
params.clear();
params.put("startTime","2020-06-03");
params.put("endTime","2020-06-30");
result = dao.find(params);
Assert.assertEquals(2,result.size());
params.clear();
params.put("title","spring");
List<News> results = dao.find(params);
Assert.assertEquals(1,results.size());
}
三。将动态查询,并作为⼀个独⽴功能开发出来。
⾸先⼀个⼩功能:在登陆时,如果已登录显⽰欢迎,没登陆则提⽰登录
<h1>${user !=null ? "欢迎".concat(user.nickname):"请"}登陆</h1>
输出参数:问⽅法要结果。c#中有ref。这⾥直接定义了⼀个map传值进去,然后再⽅法⾥进⾏赋值,之后直接使⽤即可,如下outparams. eg:
Map<String ,Object> params=new HashMap<>();//请求参数
String[] strings, Map<String,
Object> outParams) {
for(int i=0;i<strings.length;i++) {
String name = strings[i];  // 当前请求参数名字
String value = Parameter(name);
if (value != null) {
value = im();
if (value.length() > 0) {
outParams.put(name, value);
}
}
}
}
⽬标:在新闻列表页,增加新闻分类,时间的选择,关键词进⾏筛选新闻。
1,实现以关键字进⼊,并且把关键字展⽰,之后通过新闻分类进⾏筛选,并且点的新闻分类会变红。
实现如下
<p><a href="/index.jsp">⾸页</a>/新闻</p>
<h1>新闻列表</h1>
<div>
<div>全部结果>${params.keywords}</div>