(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