(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.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.realname,
             u.phone,
             u.email,
             u.address,
             u.create_time u_create_time,
             r.id r_id,
             r.content r_content,
             r.users_id r_users_id,
             r.news_id r_news_id,
             r.create_time r_create_time,
             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 on r.news_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 = req.getParameter("op");
        if("list".equals(op)){
            list(req,resp);
        }else if("find".equals(op)){
            find(req,resp);
        }
        /*NewsMapper newDao=MybatisUtils.getMapper(NewsMapper.class);
        List<News> list=newDao.findAllComplex();
        //将查询到的数据库信息存储得到“请求作用域”
        req.setAttribute("list",list);//前面一个
        req.getRequestDispatcher("/news/list.jsp").forward(req,resp);*/

    }
    private void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        NewsMapper newDao=MybatisUtils.getMapper(NewsMapper.class);
        List<News> list=newDao.findAllComplex();
        //将查询到的数据库信息存储得到“请求作用域”
        req.setAttribute("list",list);//前面一个
        req.getRequestDispatcher("/news/list.jsp").forward(req,resp);
    }

    private void find(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        NewsMapper newsDao = MybatisUtils.getMapper(NewsMapper.class);
        int newsId = StringUtil.getInt(req,"id");
        News news = newsDao.findNewsWithReplys(newsId);
        // 将查询到的数据库信息存储到“请求作用域”
        req.setAttribute("news", news);
        req.getRequestDispatcher("/news/detail.jsp").forward(req, resp);
    }
}

 

完善新闻详情界面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/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>
      ${news.content}
    </div>
    <h3>评论</h3>
    <hr/>
    <div>
      <ul>
        <c:forEach items="${news.replys}" var="reply">
        <li>${reply.content} - ${reply.createTimeString}</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)进行查询,如果用户没有提供分类查询则查询所有的新闻,否则查询指定分类的新闻。

1.xml文件添加的内容

为什么使用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">
        select
             n.id,
             concat(substring(n.title,1,8),if(char_length(n.title)>8,'...','')) title,
             concat(substring(n.content,1,8),if(char_length(n.content)>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.realname,
             u.phone,
             u.email,
             u.address,
             u.create_time u_create_time,
             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 &lt;= #{endTime}
            </if>
            <if test="title != null and title.trim().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 &lt;= #{endTime}
            </if>
            <if test="title != null and title.trim().length() > 0">
                and n.title = #{title}
            </if>
        

 

2.添加方法:

List<News> find(Map<String, Object> params);

3.单元测试

 @Test
    public void find(){
        NewsMapper dao=MybatisUtils.getMapper(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<>();//请求参数
        StringUtil.getParameters(req,new String[]{"keywords","category_id"},params);//此时params是空的,是一个输出参数,在方法中进行了获取参数
  public static void getParameters(HttpServletRequest req,
                                     String[] strings, Map<String,
                                    Object> outParams) {
        for(int i=0;i<strings.length;i++) {
            String name = strings[i];  // 当前请求参数名字
            String value = req.getParameter(name);
            if (value != null) {
                value = value.trim();
                if (value.length() > 0) {
                    outParams.put(name, value);
                }
            }
        }
    }

目标:在新闻列表页,增加新闻分类,时间的选择,关键词进行筛选新闻。

1,实现以关键字进入,并且把关键字展示,之后通过新闻分类进行筛选,并且点的新闻分类会变红。

 

 实现如下

<p><a href="/index.jsp">首页</a>/新闻</p>
    <h1>新闻列表</h1>
      <div>
        <div>全部结果>${params.keywords}</div>
        <div>
          <table>
            <tr>
              <td>新闻分类:</td>
              <td>
                <span><a   ${ params.category_id ==null?"style=\"color:red;\"":""}                 //看是否为空,为空即为红色
                        href="/news/list?op=list&keywords=${params.keywords}">全部</a></span>&nbsp;            //传递关键词
                <c:forEach items="${categorys}" var="category">                             //循环
                  <span  >
                    <a   ${category.id == params.category_id ?"style=\"color:red;\"":""}              //验证分类是否为红色
                         href="/news/list?op=list&category_id=${category.id}&keywords=${params.keywords}">    //传递参数
                      ${category.name}
                    </a>
                  </span>&nbsp&nbsp;
                </c:forEach>
              </td>
            </tr>
          </table>
        </div>

     </div>

 2.增加时间段筛选

 

 首先增加对时间段的处理方法:

public static void getInterval(HttpServletRequest req,
                                   String interval,
                                   String startTime,
                                   String endTime,
                                   Map<String, Object> outParams) {
        // 如何把时间段解析为时间点?时间如何转换?
        int intValue = getInt(req,interval);      //获取时间段
        Calendar cl = Calendar.getInstance();     //获取当前时间
        String endTimeValue = format(cl.getTime());
        // 没有传递interval值或者查询最近
        if(intValue <= 0){
            cl.add(Calendar.WEEK_OF_YEAR,-1);          //上一周
        }else{ // 若干月以前
            cl.add(Calendar.MONTH,-intValue);          
        }
        // 将起始截止时间点存储到输出集合中
        String startTimeValue = format(cl.getTime());
        outParams.put(interval,intValue); // 回显参数
        // 传递给dao层的
        outParams.put(startTime,startTimeValue);
        outParams.put(endTime,endTimeValue);
    }


static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static String format(Date pubtime) {
        return pubtime != null ? df.format(pubtime) : "";
    }



 public static int getInt(HttpServletRequest req, String id) {
        String value = req.getParameter(id);
        try {
            int intValue = Integer.parseInt(value);
            return intValue;
        }catch (NumberFormatException e){
        }
        return -1;
    }

 然后再servlet中调用此方法:

 private void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 两次查询打开了几次数据库? 一次
        NewsMapper newsDao = MybatisUtils.getMapper(NewsMapper.class);
        CategorysMapper categorysDao = MybatisUtils.getMapper(CategorysMapper.class);
        // bean params作为查询bean使用的,实体bean,业务bean
        // params作用:接收参数、回显参数
        Map<String,Object> params = new HashMap<>(); // 请求参数
        // 获取请求参数
        StringUtil.getParameters(req,new String[]{"keywords","category_id"},params);
        StringUtil.getInterval(req,"interval","startTime","endTime",params);
        List<News> list = newsDao.find(params);
        List<Categorys> categorys = categorysDao.findAll();
        // 将查询到的数据库信息存储到“请求作用域”
        req.setAttribute("categorys",categorys);
        req.setAttribute("params",params);
        req.setAttribute("list", list);
        req.getRequestDispatcher("/news/list.jsp").forward(req, resp);
    }

在页面中进行联合检索,关键字,分类,时间联合查询:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
  <head>
    <title>新闻列表</title>
    <style type="text/css">
      .usersInfo{
        display:none;
        width:200px;
        background:#eee;
        border:1px solid #333;
        position:absolute;/*把定位改为绝对定位,即弹出usersinfo中的内容*/
      }
    </style>
    <script type="text/javascript" src="/js/jquery-1.8.3.min.js"></script>
    <script type="text/javascript">
        $(function(){
            // 保证页面加载完成后在执行
            // 选择器.动作,hover表示是由两个函数组合而成的。其中的this指当前单元格
            $(".users").hover(function(){
                $(".usersInfo",this).css("display","block");
            },function(){
                $(".usersInfo",this).css("display","none");
            });
        });
    </script>
  </head>
  <body>
  <p><a href="/index.jsp">首页</a>/新闻</p>
    <h1>新闻列表</h1>
      <div>
        <div>全部结果>${params.keywords}</div>
        <div>
          <table>
            <tr>
              <td>新闻分类:</td>
              <td>
                <span><a   ${ params.category_id ==null?"style=\"color:red;\"":""} href="/news/list?op=list&keywords=${params.keywords}&interval=12">全部</a></span>&nbsp; <c:forEach items="${categorys}" var="category">
                  <span  >
                    <a   ${category.id == params.category_id ?"style=\"color:red;\"":""} href="/news/list?op=list&category_id=${category.id}&keywords=${params.keywords}"> ${category.name} </a>
                  </span>&nbsp&nbsp; </c:forEach>
              </td>
            </tr>
            <tr>
              <td>发布时间</td> <td> <span><a ${params.interval<=0 || params.intarval==null ?"style=\"color:red;\"":""} href="/news/list?op=list&keywords=${params.keywords}&interval=0&category_id=${params.category_id}">最近</a></span> <span><a ${params.interval==1 ? "style=\"color:red;\"":""} href="/news/list?op=list&keywords=${params.keywords}&interval=1&category_id=${params.category_id}">1月内</a></span> <span><a ${params.interval==3 ? "style=\"color:red;\"":""} href="/news/list?op=list&keywords=${params.keywords}&interval=3&category_id=${params.category_id}">3月内</a></span> <span><a ${params.interval==6 ? "style=\"color:red;\"":""} href="/news/list?op=list&keywords=${params.keywords}&interval=6&category_id=${params.category_id}">半年内</a></span> <span><a ${params.interval==12 ? "style=\"color:red;\"":""} href="/news/list?op=list&keywords=${params.keywords}&interval=12&category_id=${params.category_id}">1年内</a></span> </td>
            </tr>
          </table>
        </div>

     </div>
    <table width="800" border="1">
      <tr>
        <th>编号</th>
        <th>标题</th>
        <th>内容</th>
        <th>关键字</th>
        <th>作者</th>
        <th>发布</th>
        <th>审批</th>
        <th>分类</th>
      </tr>
      <c:forEach items="${list}" var="news">
      <tr>
          <td><a href="/news/list?op=find&id=${news.id}">${news.id}</a></td>
        <td>${news.title}</td>
        <td>${news.content}</td>
        <td>${news.keywords}</td>
        <td class="users">${news.owner.nickname}
          <div class="usersInfo">
            <table>
              <tr>
                <td>账号</td>
                <td>${news.owner.nickname}</td>
              </tr>
              <tr>
                <td>姓名</td>
                <td>${news.owner.realname}</td>
              </tr>
              <tr>
                <td>电话</td>
                <td>${news.owner.phone}</td>
              </tr>
              <tr>
                <td>邮件</td>
                <td>${news.owner.email}</td>
              </tr>
              <tr>
                <td>地址</td>
                <td>${news.owner.address}</td>
              </tr>
            </table>
          </div>
        </td>
        <td>${news.pubtimeString}</td>
        <td>${news.checkUsersName}</td>
        <td>${news.categoryName}</td>

      </tr>
      </c:forEach>
    </table>
  </body>
</html>

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM