Springcloud微服務項目——人力資源管理(HRM)Day06 ElasticSearch

今日任務
在這裏插入圖片描述

課程的CRUD

關於數據庫的存儲

有兩種方案
方案一:
像課程詳情 課程圖片 都是數據課程的信息 可知直接放入t_course 就ok
方案二:
有時候我們只需要查詢到課程的基本信息 不需要顯示圖片和詳情 這個時候我們就會用到垂直分表

垂直分表:一些字段我們一般不需要直接查詢 就把這些字段單獨放一個表 通過外鍵關聯 正常情況下 不需要查詢關聯表 如果需要 就通過外鍵查詢就ok 這樣能大大提高數據庫的效率

生成代碼

生成後測試是否已經加入

在這裏插入圖片描述
然後從我們的資料中拷貝Course.vue界面
在這之前 我們需要集成一個支持Vue的富文本編輯器
直接在終端運行
npm install quill --save
npm install --save vue-quill-editor

然後把list一系列的修改了 和之前一樣
然後啓動前後端服務

然後可能會報一個這樣的錯
在這裏插入圖片描述
別擔心 這是因爲你的redis沒有啓動起來 將redis啓動就行了

這與頁面就能出來了

接下來我們來做新增操作
在這裏插入圖片描述

頁面都已經寫好 我們只需要拷貝下來用就是了 因爲我不是專業的前端 所以我們就直接用別人寫好的就行了

後臺:
我們需要修改的地方是 覆寫service中的插入和修改方法 因爲我們這個是有關聯對象的 所以自帶的方法已經滿足不了我們了

@Override
public boolean insert(Course entity) {
    //要添加三張表 課程表 詳情表 市場信心表
    //tenantId tenantName userId userName
    System.out.println(entity);
    entity.setStatus(0);
    courseMapper.insert(entity);
    Long courseId = entity.getId();
    //同時保存詳情和市場信心
    CourseDetail courseDetail = entity.getCourseDetail();
    courseDetail.setCourseId(courseId);
    courseDetailMapper.insert(courseDetail);
    CourseMarket courseMarket = entity.getCourseMarket();
    courseMarket.setCourseId(courseId);
    courseMarketMapper.insert(courseMarket);
    return true;
}

對於Controller 在我麼登錄之後 需要傳遞一些信息進去 但是我們現在還用不到 所以就先註釋掉

@PutMapping
public AjaxResult addOrUpdate(@RequestBody Course course){
    try {
        // @TODO 以後登錄成功都能獲取,現在使用holder來模擬
        //登錄成功後設置到UserInfoHolder,以後所有模塊要使用都直接使用UserInfoHolder
//            course.setTenantId(UserInfoHolder.getTenant().getId());
//            course.setTenantName(UserInfoHolder.getTenant().getCompanyName());
//            course.setUserId(UserInfoHolder.getLoginUser().getId());
//            course.setUserName(UserInfoHolder.getLoginUser().getUsername());
        if(course.getId()!=null){
            courseService.updateById(course);
        }else{
            courseService.insert(course);
        }

        return AjaxResult.me();
    } catch (Exception e) {
        e.printStackTrace();
        return AjaxResult.me().setMessage("保存對象失敗!"+e.getMessage());
    }
}

修改和刪除我就不在這展示了 和之前的都大同小異


課程的上線和下線

業務說明

上線:
現實生活中:
當培訓機構研發出新的課程後,準備招生時,要先把它添加到數據中。但是期望暫時不需要用戶能夠搜索到。所以需要上線才能操作
系統中:
在系統中,我們添加了一個課程,用戶不立即解就搜索到,需要上線以後才行.
下線:
當某個課程不想賣的時候,就要下線. 當課程下線後,用戶不能搜索到,但是數據庫是還有的.

方案-用es查詢代替數據庫查詢

上線後,修改狀態爲”上線”,前臺用戶搜索時只能搜索到上線狀態的.如果不想賣了,執行下線時,修改狀態下線就ok.----------垃圾(每次都要操作數據庫.)

如果有1000W的併發來查詢課程,要高併發訪問數據庫,效率低下


上線時把課程數據同步到es,用戶查詢直接從es查詢.也就意味着沒有上線的課程用戶查詢不到,因爲沒有放到es庫.
下線時把es庫課程數據刪除掉. 用戶就查詢不到了. —NB(以基於索引搜索代替數據庫查詢)

好處:
降低數據庫壓力
提高了查詢速度,增強用戶體驗-基於索引搜索,效率遠遠數據庫搜索


ES java操作

準備es環境

Es服務端

方案選擇

  1. 原生ESTransport Client方式 —> 就相當於寫jdbc代碼,非常麻煩.
  2. Springboot spring data es
    spring data
    是spring對數據訪問抽象.這些數據可以放入db,index,nosql等包含以下:
    spring data jpa spring對關係型數據庫訪問支持
    spring data ES spring對es數據訪問支持
    spring data redis等 spring對redis數據訪問支持
    spring data …

Springboot spring data es —>對 spring data es簡化了配置

安裝和使用

如果你是第一次安裝elasticsearch 需要修改一下配置

在這裏插入圖片描述
這裏面的所需的運存改爲1g 當然 你電腦如果運存的大的話也可以不換
在這裏插入圖片描述
然後是啓動 雙擊這個文件夾就行
在這裏插入圖片描述
直接就啓動了
在這裏插入圖片描述
他有兩個端口 一個是9200 一個是9300 9300是代碼訪問的客戶端 9200是http的
然後再瀏覽器中訪問
http://localhost:9200/
如果能看到這個界面 就說明是成功了
在這裏插入圖片描述
接下來我們使用kibana來訪問她 首先要啓動kibana的服務

首先修改一下配置 指定端口
在這裏插入圖片描述

然後啓動(儘量使用管理員權限啓動)在這裏插入圖片描述
啓動成功後
在這裏插入圖片描述
我們在瀏覽器中訪問
http://localhost:5601/

在這裏插入圖片描述

我們用的最多的是
在這裏插入圖片描述
其他的喜歡研究的可以自己去研究一下

課程上下線實現

技術架構

在這裏插入圖片描述

管理員:(千級)
添加:直接操作數據庫
刪除和修改: 同步操作方案
分頁查詢:直接操作數據.併發量小.
上線:同步信息到ES庫.
下線:刪除ES庫數據
用戶:(千萬級)
搜索課程:直接從ES

實現

寫的服務不具備通用性,沒必要單獨搞一個服務

關於數據庫的設計

需要值得注意的是 :這裏我們的數據庫採用的是反3NF的設計

在這裏插入圖片描述

準備環境 -在自己模塊

導包

<!--springboot 對spring data es支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

配置文件

spring:
  data:
    elasticsearch:
      cluster-name: elasticsearch
      cluster-nodes: 127.0.0.1:9300 #9200是圖形界面端,9300代碼端

入口類

@SpringBootApplication
public class ESApplication {
    public static void main(String[] args) {
        SpringApplication.run(ESApplication.class);
    }
}

EsCourse.java

//包含了前臺展示的字段和要添加到索引庫都要寫到這兒
@Document(indexName = "hrm",type = "course")
public class EsCourse {
    @Id
    private Long id;
    private String name;
    private String users;
    private Long courseTypeId;
    private String courseTypeName;
    private Long gradeId;
    private String gradeName;
    private Integer status;
    private Long tenantId;
    private String tenantName;
    private Long userId;
    private String userName;
    private Date startTime;
    private Date endTime;
    private String intro;
    private String resources; //圖片
    private Date expires; //過期時間
    private BigDecimal priceOld; //原價
    private BigDecimal price; //原價
    private String qq; //原價

    @Field(type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
    private String all;

	//getter和setter

	//toString

public String getAll() {
        String tmp =  name
        +" "+ users
        +" "+ courseTypeName
        +" "+ gradeName
        +" "+ tenantName
        +" "+ userName
        +" "+ intro;
        return tmp;
    }

EsCourseRepository.java

import org.leryoo.index.doc.EsCourse;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

//在service通過注入它就可以完成索引庫操作了
public interface EsCourseRepository extends ElasticsearchRepository<EsCourse,Long> {
}

接下來什麼地方要用到就直接調用就行了 和操作數據庫的方法都差不多


Service層 業務邏輯
上線

@Override
public AjaxResult onLine(Long[] ids) {
    try
    {
        //1添加索引庫
        // 通過id查詢數據庫裏面課程
        List<Course> courses = courseMapper
                .selectBatchIds(Arrays.asList(ids));
        //轉換爲doc
        List<EsCourse> esCourses = courses2EsCourses(courses);
        //批量添加就ok
        repository.saveAll(esCourses);
        //2 修改數據庫狀態和上線時間 - ids,time
        Map<String,Object> params = new HashMap<>();
        params.put("ids",ids);
        params.put("onLineTime",new Date());
        // 修改狀態和上線時間
        //update t_couse set status=1 and start_time={} where id in (1,2,3,4)
        courseMapper.onLine(params);
        return AjaxResult.me();
    }catch (Exception e){
        e.printStackTrace();
        return AjaxResult.me().setSuccess(false).setMessage("上線失敗!"+e.getMessage());
    }

}


private List<EsCourse> courses2EsCourses(List<Course> courses) {
    //1 聲明要返回
    List<EsCourse> result = new ArrayList<>();
    //2 轉換
    for (Course course : courses) {
        result.add(course2EsCourse(course));
    }
    //3返回
    return  result;
}



//把一個course轉換爲EsCourse
private EsCourse course2EsCourse(Course course) {
    //1 聲明要返回
    EsCourse result = new EsCourse();
    //  2 轉換
    result.setId(course.getId());
    result.setName(course.getName());
    result.setUsers(course.getUsers());
    result.setCourseTypeId(course.getCourseTypeId());
    //type-同庫-沒有做關聯查詢
    if (course.getCourseType() != null)
        result.setCourseTypeName(course.getCourseType().getName());
    result.setGradeId(course.getGrade());
    result.setGradeName(course.getGradeName());
    result.setStatus(course.getStatus());
    result.setTenantId(course.getTenantId());
    result.setTenantName(course.getTenantName());
    result.setUserId(course.getUserId());
    result.setUserName(course.getUserName());
    result.setStartTime(course.getStartTime());
    result.setEndTime(course.getEndTime());
    //Detail
    result.setIntro(null);
    //resource
    result.setResources(null);
    //market
    result.setExpires(null);
    result.setPrice(null);
    result.setPriceOld(null);
    result.setQq(null);
    //   3返回
    return result;
}

下線:

@Override
public AjaxResult offLine(Long[] ids) {
    try
    {
        //1 刪除索引庫裏面的內容
        //        List<Course> courses = courseMapper
        //                .selectBatchIds(Arrays.asList(ids));
        //轉換爲doc
        //        List<EsCourse> esCourses = courses2EsCourses(courses);
        //        repository.deleteAll(esCourses);
        for (Long id : ids) {
            repository.deleteById(id);
        }
        //2 修改數據庫狀態 status=0 end_time
        Map<String,Object> params = new HashMap<>();
        params.put("ids",ids);
        params.put("offLineTime",new Date());
        // 修改狀態和下線時間
        //update t_couse set status=0 and start_time={} where id in (1,2,3,4)
        courseMapper.offLine(params);
        return AjaxResult.me();
    }catch (Exception e){
        e.printStackTrace();
        return AjaxResult.me().setSuccess(false).setMessage("下線失敗!"+e.getMessage());
    }

}

SQL語句

<!--    上線-->
<!--    void onLine(Map<String, Object> params);-->
<update id="onLine" parameterType="map">
    update t_course set status=1,start_time=#{onLineTime} where id in
    <foreach collection="ids" separator="," open="(" close=")" item="id">
        #{id}
    </foreach>
</update>


<!--    void offLine(Map<String, Object> params);-->
<update id="offLine" parameterType="map">
    update t_course set status=0 , end_time=#{offLineTime} where id in
    <foreach collection="ids" separator="," open="(" close=")" item="id">
        #{id}
    </foreach>
</update>

注意前端傳參
在這裏插入圖片描述
和封裝參數
在這裏插入圖片描述
和選中行時往sels裏面傳值
在這裏插入圖片描述
需要注意的是 傳值的時候 Controller層需要加上

在這裏插入圖片描述
然後編寫SQL語句的時候
在這裏插入圖片描述
這裏直接寫參數
自此 課程模塊就已經寫完了

今天的內容就到這啦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章