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语句的时候
在这里插入图片描述
这里直接写参数
自此 课程模块就已经写完了

今天的内容就到这啦

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