一、簡介

時序圖:

二、參數列表

參數名

描述

類型

默認值

條件

currentPage

當前頁數

Integer


非必須

pageSize

一頁數據數量

Integer


非必須

三、接口規範

[請求] /activity/find-list?currentPage=1&pageSize=10 GET
[響應] 
{
 "code": 200,
"data": {
	 "total": 10,
		 "records": [
			 {
				 "activityId": 23,
				 "activityName": "抽獎測試",
				 "description": "年會抽獎活動",
				 "valid": true
			 },
			 {
				 "activityId": 22,
				 "activityName": "抽獎測試",
				 "description": "年會抽獎活動",
				 "valid": true
			 },
			 {
				  "activityId": 21,
				 "activityName": "節⽇抽獎",
				 "description": "⽐特年會抽獎活動",
				 "valid": true
			 }
		 ]
	 },
 "msg": ""
}

四、Controller 層

com/yj/lottery_system/controller 包下 ActivityController類中:

  • 調用前面獎品列表展示的PageParam 分頁查詢的參數,作為參數
  • 調用service層,
  • convertTOFindActivityListResult:將service返回值轉換為Controller層
  • 返回
@RequestMapping(" /activity/find-list")
    public CommonResult<FindActivityListResult> findActivityList(PageParam param) {
        //日誌打印
        log.info("findActivityList PageParam: {}", JacksonUtil.writeValueAsString(param));
        //調用service服務
        return CommonResult.success(convertTOFindActivityListResult( activityService.findActivityList(param)));
    }

4.1 FindActivityListResult:Controller層返回值

com.yj.lottery_system.controller.result 包下:

  • 根據接口規範中的響應數據返回:activityId,activityName,description,valid四個屬性
package com.yj.lottery_system.controller.result;

import lombok.Data;

import java.io.Serializable;
import java.util.List;

@Data
public class FindActivityListResult implements Serializable {
    //活動總數
    private Integer total;
    //當前頁活動列表
    private List<FindActivityListResult.ActivityInfo> records;
    @Data
    public static class  ActivityInfo implements Serializable {
        //活動id
        private Long activityId;

        //活動名
        private String activityName;

        //活動描述
        private String description;

        //活動是否結束
        private Boolean valid;


    }
}

4.2 convertTOFindActivityListResult:將service返回值轉換為Controller層

com/yj/lottery_system/controller 包下 ActivityController類中:

  • 非空判斷
  • 將service層返回值一一賦值給Controller層返回數據
private FindActivityListResult convertTOFindActivityListResult(PageListDTO<ActivityDTO> activityList) {
        if(null == activityList) {
            throw new ControllerException(ControllerErrorCodeConstants.FIND_ACTIVITY_LIST_ERROR);
        }
        FindActivityListResult findActivityListResult = new FindActivityListResult();
        findActivityListResult.setTotal(activityList.getTotal());
        findActivityListResult.setRecords(activityList.getRecords().stream()
                .map( activityDTO -> {
                    FindActivityListResult.ActivityInfo activityInfo = new FindActivityListResult.ActivityInfo();
                    activityInfo.setActivityId(activityDTO.getActivityId());
                    activityInfo.setActivityName(activityDTO.getActivityName());
                    activityInfo.setDescription(activityDTO.getDescription());
                    activityInfo.setValid(activityDTO.valid());
                    return activityInfo;
                }).collect(Collectors.toList())
        );
        return findActivityListResult;
    }

4.3 新增錯誤碼

com/yj/lottery_system/common/errorcode 包下:ControllerErrorCodeConstants類中:

ErrorCode FIND_ACTIVITY_LIST_ERROR = new ErrorCode(301,"查詢活動列表失敗");

五、service層

5.1 創建接口

com/yj/lottery_system/service 包下:IActivityService接口類中:

/**
     * 分頁獲取活動列表
     * @param param
     * @return
     */
    PageListDTO<ActivityDTO> findActivityList(PageParam param);

5.2 實現接口

com/yj/lottery_system/service/impl 包下 ActivityServiceImpl類中:

  • 調用dao獲取活動總數
  • 調用dao獲取當前頁活動列表
  • 將dao層返回數據,一一賦值給service返回數據
  • 返回
/**
     * 分頁獲取活動基本信息列表
     * @param param
     * @return
     */
    @Override
    public PageListDTO<ActivityDTO> findActivityList(PageParam param) {
        //獲取總量
        int total = activityMapper.count();
        //獲取當前頁活動列表
        int offset = (param.getCurrentPage() - 1) * param.getPageSize();
        List<ActivityDO> activityDOList = activityMapper.selectActivityList(offset,param.getPageSize());
        List<ActivityDTO> activityDTOList = activityDOList.stream()
                .map(activityDO -> {
                    ActivityDTO activityDTO = new ActivityDTO();
                    activityDTO.setActivityId(activityDO.getId());
                    activityDTO.setActivityName(activityDO.getActivityName());
                    activityDTO.setDescription(activityDO.getDescription());
                    activityDTO.setStatus(ActivityStatusEnum.forName(activityDO.getStatus()));

                    return activityDTO;
                }).collect(Collectors.toList());
        
        return new PageListDTO<>(total,activityDTOList);
    }

5.3 service層返回數據

com.yj.lottery_system.service.dto包下:

  • 根據返回值,設置四個屬性
  • 並且與controller層對應,提供判斷活動狀態的 valid 方法。
package com.yj.lottery_system.service.dto;

import com.yj.lottery_system.service.enums.ActivityStatusEnum;
import lombok.Data;

import java.io.Serializable;
@Data
public class ActivityDTO implements Serializable {
    //活動id
    private Long activityId;

    //活動名
    private String activityName;

    //活動描述
    private String description;

    //活動狀態
    private ActivityStatusEnum status;

    //活動是否結束
    public Boolean valid() {
        return status.equals(ActivityStatusEnum.RUNNING);
    }
}

六、dao層

com/yj/lottery_system/dao/mapper 包下 ActivityMapper:

/**
     * 查詢活動總數
     * @return
     */
    @Select("select count(1) from activity")
    int count();

    /**
     * 查詢當前頁面的獎品列表
     * @param offset
     * @param pageSize
     * @return
     */
    @Select("select * from activity order by id desc limit ${offset}, #{pageSize}")
    List<ActivityDO> selectActivityList(@Param("offset") Integer offset,
                                        @Param("pageSize") Integer pageSize);

七、測試

八、前端

static/activities-list.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>活動列表</title>
  <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/bootstrap/4.5.2/css/bootstrap.min.css">
  <link rel="stylesheet" href="./css/base.css">
  <style>
    body {
      font-family: Arial, sans-serif;
      background-color: #f2f2f2;
    }
    .activity-list {
      padding:0 30px;
    }
    #activities{
      height: calc(100vh - 134px);
      overflow-y: auto;
      padding-right: 10px;
    }
    .activity-item {
      display: flex;
      align-items: center;
      justify-content: space-between;
      background-color: #f7f7f7;
      padding: 24px;
      border-radius: 4px;
      overflow: hidden;
      margin-bottom: 10px;
      border-radius: 8px;
      padding-bottom: 12px;
    }
    .activity-info{
      width: calc(100% - 120px);
    }
    .activity-info h4{
      width: 100%;
      font-weight: 600;
      font-size: 15px;
      color: #000000;
      margin-bottom: 4px;
    }
    .activity-info p{
      font-weight: 400;
      font-size: 14px;
      color: #666666;
      margin: 0;
      line-height: 28px;
    }
    .active a{
      font-weight: 400;
      font-size: 15px;
      color: red;
      margin-bottom: 0;
      display: block;
      width: 250px;
    }
    .inactive a{
      font-weight: 400;
      font-size: 15px;
      color: gray;
      margin-bottom: 0;
      display: block;
      width: 250px;
    }
    .pagination {
      display: flex;
      justify-content: flex-end;
      margin-top: 18px;
      padding-right: 16px;
    }
    .pagination button {
      margin: 0 5px; /* 按鈕之間的間距保持不變 */
      border-radius: 5px; /* 設置圓角為20像素,可以根據需要調整 */
      border: 1px solid #007bff;
      background-color: #fff;
      padding: 0px 8px; /* 可以添加一些內邊距,使按鈕看起來更飽滿 */
      cursor: pointer; /* 將鼠標光標改為指針形狀,提升用户體驗 */
      font-size: 13px;
    }
    .pagination span{
      margin: 0 10px;
      font-size: 14px;
    }
    .pagination input{
      width: 80px;
      text-align: center;
    }
    .activity-list h2 {
      font-weight: 600;
      font-size: 18px;
      color: #000000;
      height: 70px;
      display: flex;
      align-items: center;
      margin-bottom: 0;
    }
  </style>
</head>
<body style="background-color: white">
<div class="activity-list">
  <h2>活動列表</h2>
  <div id="activities">
    <!-- 活動列表將動態插入這裏 -->
  </div>
  <div class="pagination">
    <button class="btn-outline-primary" onclick="fetchActivities(1)">首頁</button>
    <button class="btn-outline-primary" onclick="previousPage()">上一頁</button>
    <span>第 <input type="number" id="pageInput" min="1" value="1" /> 頁</span>
    <button class="btn-outline-primary" onclick="nextPage()">下一頁</button>
    <button class="btn-outline-primary" onclick="fetchActivities(totalPages)">尾頁</button>
  </div>
</div>

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="./js/toastr.min.js"></script>
<script>
    var currentPage = 1;
    var pageSize = 10;
    var totalPages;
    var userToken = localStorage.getItem("user_token");

    // 發送AJAX請求的函數
    function fetchActivities(page) {
      // 如果頁碼小於1,則重置為1
      if (page < 1) {
        page = 1;
      }
      // 更新當前頁碼
      currentPage = page;
      // 構建要發送的數據對象
      var dataToSend = {
        currentPage: currentPage,
        pageSize: pageSize
      };
      // 發送AJAX請求
      $.ajax({
          url: '/activity/find-list',
          type: 'GET',
          data: dataToSend, // 將分頁參數作為請求數據發送
          dataType: 'json',
          headers: {
            // jwt
            "user_token": userToken
          },
          success: function(result) {
            if (result.code != 200) {
                alert("查詢活動列表失敗!" + result.msg);
            } else {
                var activities = result.data.records; // 假設返回的數據中活動列表字段為 'records'
                var activitiesHtml = '';
                var listContainer = document.getElementById('activities');
                // 在添加新內容前,先清空listContainer
                listContainer.innerHTML = '';
                activities.forEach(function(activity) {
                  var url = 'draw.html?activityName='+ encodeURIComponent(activity.activityName)
                          +'&activityId=' + encodeURIComponent(activity.activityId)
                          +'&valid=' + encodeURIComponent(activity.valid);
                  var linkTextActive = `<a href="${url}" target="_blank">活動進行中,去抽獎</a>`;
                  var linkTextInactive = `<a href="${url}" target="_blank">活動已完成,查看中獎名單</a>`;
                  var validClass = activity.valid ? 'active' : 'inactive';
                  var link = activity.valid ? linkTextActive : linkTextInactive;
                  activitiesHtml += `
                      <div class="activity-item">
                        <div class="activity-info">
                          <h4>${activity.activityName}</h4>
                          <p>${activity.description}</p>
                        </div>
                        <div class="${validClass}">
                          <p>${link}</p>
                        </div>
                      </div>
                    `;
                });
                $('#activities').html(activitiesHtml);
                // 更新分頁控件的總頁數
                totalPages = Math.ceil(result.data.total / pageSize);
                // 更新輸入框的值
                $('#pageInput').val(currentPage);
              } // else end
          },
        error:function(err){
          console.log(err);
          if(err!=null && err.status==401){
            alert("用户未登錄, 即將跳轉到登錄頁!");
            // 跳轉登錄頁
            window.location.href = "/blogin.html";
            window.parent.location.href = "/blogin.html";//讓父頁面一起跳轉
          }
        }
      });
    }


    function previousPage() {
      if (currentPage > 1) {
        fetchActivities(currentPage - 1);
      } else {
        alert("已經是第一頁");
      }
    }

    function nextPage() {
      if (currentPage < totalPages) {
        fetchActivities(currentPage + 1);
      } else {
        alert("已經是最後一頁");
      }
    }

    $(document).ready(function() {
      fetchActivities(1);
    });

    // 綁定輸入框回車事件
    $('#pageInput').on('keypress', function(e) {
      if (e.key === 'Enter') {
        var page = parseInt(this.value);
        if(page > totalPages){
          page = totalPages
          $('#pageInput').val(totalPages);
        }
        if (!isNaN(page) && page >= 1 && page <= totalPages) {
          fetchActivities(page);
        }
      }
    });

</script>
</body>
</html>