ProjectDay17

续 迁移用户信息面板功能

完成Sys模块调用

上次课我们完成了Faq模块的Rest接口的开发

下面要在sys模块中调用这个接口

转到knows-sys模块

UserServiceImpl业务逻辑层实现类

getUserVO方法中,利用Ribbon调用Faq模块的根据用户id查询问题数(收藏数)的方法

// 添加Ribbon支持
// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
@Resource
private RestTemplate restTemplate;

@Override
public UserVO getUserVO(String username) {
    // 根据用户名查询用户
    User user=userMapper.findUserByUsername(username);
    // 根据用户id查询问题数 和收藏数(作业)
    // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    String url=
      "http://faq-service/v2/questions/count?userId={1}";
    Integer count=restTemplate.getForObject(
            url,Integer.class,user.getId());
    // (作业)调用方法获得当前用户的收藏数......
    // 实例化UserVO对象赋值并返回
    UserVO userVO=new UserVO()
            .setId(user.getId())
            .setUsername(user.getUsername())
            .setNickname(user.getNickname())
        // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
            .setQuestions(count);
    //(作业) 赋值收藏数到userVO对象
    // 别忘了返回userVO
    return userVO;
}

添加拦截器路径

控制器不需要修改

只需要将拦截器配置到路径,让拦截器在控制器运行前解析用户信息即可

sys模块的WebConfig类中添加拦截器路径

// 配置解析Jwt的拦截器生效
registry.addInterceptor(authInterceptor)
        .addPathPatterns(
                "/v1/home",     // 判断身份跳转首页
                "/v1/users/me"  // 根据用户返回面板信息
        );

前端axios调用修改

knows-client项目

user_info.js

axios({
    url:"http://localhost:9000/v1/users/me",
    method:"get",
    params:{
        accessToken:token
    }
})

启动Nacos\gateway\auth

启动faq\sys\client

登录学生或讲师,观察首页用户信息面板内容

迁移文件上传功能

微服务环境下,我们的上传功能由knows-resource模块来负责

转到knows-resource模块

创建controller包

包中创建ImageController类,来编写上传文件的代码

将portal项目中SystemController中上传代码复制到这个类中即可

复制后代码如下

@RestController
// 因为项目设置了全局路径/image
// 所以这个控制方法实际访问路径为 /image/file
@RequestMapping("/file")
@Slf4j
public class ImageController {

    // 从application.properties文件中获得配置信息的代码
    @Value("${knows.resource.path}")
    private File resourcePath;
    @Value("${knows.resource.host}")
    private String resourceHost;

    // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    @PostMapping
    public String upload(MultipartFile imageFile) throws IOException {
        // 代码没有修改
        // 略....
    }
    
}

代码中使用@Value注解从application.properties配置文件中获得需要的信息,现在knows-resource项目中并没有配置

所以到配置文件中添加:

# 上传文件需要的路径和服务器端口
knows.resource.path=file:F:/upload
knows.resource.host=http://localhost:9000/image

ImageController类上添加跨域注解实现跨域

// 跨域注解
@CrossOrigin
public class ImageController {
    //...
}

这个跨域注解适合当前项目只有少量控制器类时

转到knows-client项目

修改question/create.html页面中底部的js代码,上传的路径修改为

axios({
  url:"http://localhost:9000/image/file",
  method:"post",
  data:form
})

启动knows-resource项目

重启knows-client

之前已经启动的服务不要停止

Nacos\gateway\auth\sys\faq

测试在create.html页面上的上传功能

迁移问题详情页

我们已经迁移了我们单体项目中的大部分功能

最后剩下的就是问题详情页的内容了

转到knows-faq模块完成最后的迁移工作

迁移数据访问层

本次迁移目标围绕answer回答和comment评论

在这里插入图片描述

先复制两个Mapper接口,导包就能解决错误

再复制xml文件到faq模块

代码如下

<mapper namespace="cn.tedu.knows.faq.mapper.AnswerMapper">
                           <!-- ↑↑↑↑↑  -->
    <!-- 回答包含评论集合的映射结果 -->
    <resultMap id="answerCommentMap" 
               type="cn.tedu.knows.commons.model.Answer">
       						   <!-- ↑↑↑↑↑  -->
        <id     column="id"             property="id" />
        <result column="content"        property="content" />
        <result column="like_count"     property="likeCount" />
        <result column="user_id"        property="userId" />
        <result column="user_nick_name" property="userNickName" />
        <result column="quest_id"       property="questId" />
        <result column="createtime"     property="createtime" />
        <result column="accept_status"  property="acceptStatus" />

        <collection property="comments"
              ofType="cn.tedu.knows.commons.model.Comment">
                               <!-- ↑↑↑↑↑  -->
            <id column="comment_id" property="id" />
            <result column="comment_user_id" property="userId" />
            <result column="comment_user_nick_name" property="userNickName" />
            <result column="comment_answer_id" property="answerId" />
            <result column="comment_content" property="content" />
            <result column="comment_createtime" property="createtime" />
        </collection>
    </resultMap>

    <select id="findAnswersByQuestionId" resultMap="answerCommentMap">
       略...
    </select>

</mapper>

迁移业务逻辑层

在这里插入图片描述

复制VO类和业务逻辑层接口直接导包即可

业务逻辑层实现类复制过来后发现不但需要导包,而且还需要Ribbon

两个类中需要多次相同的Ribbon请求的结果

为了减少代码冗余,我们创建RibbonClient类来提取出当前项目业务逻辑层中所有Ribbon请求尤其是多次调用的Ribbon请求的方法

在业务逻辑层实现类中需要时调用即可

RibbonClient类代码如下

// 将这个类型对象保存到Spring容器
@Component
public class RibbonClient {
    @Resource
    private RestTemplate restTemplate;
    // 根据用户名获得用户对象
    public User getUser(String username){
        String url="http://sys-service/v1/auth/user?username={1}";
        User user=restTemplate.getForObject(
                             url,User.class,username);
        return user;
    }

}

RibbonClient类中定义了根据用户名获得用户对象的方法

Answer和Comment的业务逻辑层实现类中,哪里需要哪里调用

只是别忘了实现在类中使用@Resource注解来获得RibbonClient对象

哪个类需要哪个类添加依赖注入

@Resource
private RibbonClient ribbonClient;

在需要根据用户名获得用户对象的行编写:

User user=ribbonClient.getUser(username);

迁移控制层

在这里插入图片描述

也是先导包

然后别忘了将两个控制器的路径都修改为v2开头

@RequestMapping("/v2/answers")
@RequestMapping("/v2/comments")

控制层代码处理完毕

添加拦截器生效路径

我们新迁移的多个方法都需要用户的信息

那么访问这些控制器方法的路径就要设置拦截器生效

knows-faq模块的拦截器配置要新增,以应对新迁移来的方法功能的需要

WebConfig类中再次添加拦截器配置路径如下

registry.addInterceptor(authInterceptor)
    .addPathPatterns(
        "/v2/questions",         //发布问题
        "/v2/questions/my",      //学生首页
        "/v2/questions/teacher", //讲师首页
        "/v2/answers",           //新增回答
        "/v2/answers/*/solved",  //采纳回答
        "/v2/comments",          //新增评论
        "/v2/comments/*/delete", //删除评论
        "/v2/comments/*/update"  //修改评论
    );

修改前端axios

knows-client项目

问题详情页所有axios请求都下question_detail.js文件中

修改这个js文件中所有axios请求,注意思考是否需要添加jwt信息

loadQuestion方法

axios({
    url:"http://localhost:9000/v2/questions/"+qid,
    method:"get"
})

postAnswer方法

let form=new FormData();
form.append("questionId",qid)
form.append("content",content);
form.append("accessToken",token);
axios({
    url:"http://localhost:9000/v2/answers",
    method:"post",
    data:form
})

loadAnswers方法

axios({
    url:"http://localhost:9000/v2/answers/question/"+qid,
    method:"get"
})

postComment方法

let form=new FormData();
form.append("answerId",answerId);
form.append("content",content);
form.append("accessToken",token);
axios({
    url:"http://localhost:9000/v2/comments",
    method:"post",
    data:form
})

removeComment方法

axios({
    url:"http://localhost:9000/v2/comments/"+commentId+"/delete",
    method:"get",
    params:{
        accessToken:token
    }
})

updateComment方法

let form=new FormData();
form.append("answerId",answerId);
form.append("content",content);
form.append("accessToken",token);
axios({
    url:"http://localhost:9000/v2/comments/"+commentId+"/update",
    method:"post",
    data:form
})

answerSolved方法

axios({
    url:"http://localhost:9000/v2/answers/"+answerId+"/solved",
    method:"get",
    params:{
        accessToken:token
    }
})

重启faq模块和client项目,测试上述问题详情的功能

到此为止

达内知道单体项目功能就完全迁移到微服务了!!!

Elasticsearch全文搜索引擎

软件下载

在这里插入图片描述

什么是Elasticsearch

Elastic:富有弹性的

search:搜索

简称ES

它是一个由java开发的软件

也是一个中间件,不是SpringCloud的内容,单体项目也能使用

它能实现高效的从大量数据中进行模糊查询

启动这个软件,就相当于启动了一个java项目

控制这个软件的方法就是向这个项目发送各种请求掉用它的Rest接口

这些Rest接口的功能就能对ES中的数据进行增删改查操作

ES也是将数据保存在硬盘中的

Elasticsearch是一个基于Lucene开发的搜索服务器(搜索引擎),Lucene是一套提供了搜索引擎核心功能的Api,Lucene相当于计算的Cpu,Elasticsearch相当于一台安装好的电脑

Lucene也是java语言的产物,专门针对搜索功能,但是它不能直接使用

需要进行代码实现才能完成搜索功能

Elasticsearch还有类似的竞品软件:

solr \ MongoDB

为什么需要Elasticsearch

所有关系型数据库(mysql\oracle\DB2\sqlserver)都会有一个比较严重的缺陷

执行模糊查询(条件开头是模糊查询)的查询效率非常低

一张千万级别的数据库表,进行一次模糊查询需要20秒以上

而这个模糊查询如果在ES中进行可以将效率提高100倍以上

  • Elasticsearch是java开发的,需要java环境变量
  • Elasticsearch虽然是java开发的,但是任何语言都可以使用它
  • Elasticsearch也是支持分布式部署的,满足"高并发,高可用,高性能"

Elasticsearch查询原理

ES查询原理的核心是分词索引

它会将一段文字中包含的所有词汇创建在一个索引库中

查询时,搜索所有包含这个词汇的文字,以提高查询效率

在这里插入图片描述

凡是能够按照分词索引进行查询的软件都可以称之为"全文搜索引擎"

我们常用的网站和App中的搜索功能,几乎都是由全文搜索引擎提供的

ES会将要优化查询的表的数据复制到ES的数据库中,也是复制到硬盘上

这样从ES中进行查询即使是大量数据的模糊查询,查询速度也能保持在毫秒级别

Elasticsearch的启动

官方下载链接

https://www.elastic.co/cn/downloads/past-releases#elasticsearch

将下载的280兆的压缩包解压

进入压缩包后得到如下bin目录中的内容

在这里插入图片描述

双击运行elasticsearch.bat文件,可以启动ES

在这里插入图片描述

dos窗口不能关,一关ES就停止工作了

ES没有支持开机自动启动的功能,所以每次开机需要ES时只能手动启动

怎么证明我们的ES正常工作呢

可以打开浏览器输入地址

localhost:9200
在这里插入图片描述

mac系统启动

tar -xvf elasticsearch-7.6.2-darwin-x86_64.tar.gz 
cd elasticsearch-7.6.2/bin 
./elasticsearch

linux:

tar -xvf elasticsearch-7.6.2-linux-x86_64.tar.gz
cd elasticsearch-7.6.2/bin
./elasticsearch

ES基本使用

我们安装启动好了ES软件

下面就是要调用ES提供的Rest接口,实现ES的各种功能

我们创建一个项目knows-search模块

这个项目用作实现搜索功能

在这里插入图片描述

父子相认

<module>knows-search</module>

子项目pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>cn.tedu</groupId>
        <artifactId>knows</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.tedu</groupId>
    <artifactId>knows-search</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>knows-search</name>
    <description>Demo project for Spring Boot</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

</project>

这个项目创建出来,我们先用于操作ES

在项目中创建一个http request文件(http client\http客户端)

这个文件可以编写http请求,发送给指定的服务器

现在我们的请求目标就是启动的ES:localhost:9200

在这里插入图片描述

文件名可以自定义

在文件中编写代码
在这里插入图片描述

### 这里先做最基本的ES测试
GET http://localhost:9200

### ES分词测试
POST http://localhost:9200/_analyze
Content-Type: application/json

{
  "text": "运筹帷幄之间决胜千里之外",
  "analyzer": "standard"
}

“analyzer”: "standard"是分词器的设定

默认其实就是standard是可以省略的

这个默认的分词器只能识别英文进行分词,原因是英文分词靠空格

而不能实现中文分词

我们需要安装一个插件,添加能够识别中文的分词器

这个插件的名字叫ik

在这里插入图片描述

因为安装插件相当于修改了java程序的配置

所以要想新配置生效,一定会重启java程序

关闭正在运行的ES窗口

重新打开运行

再次运行分词代码

{
  "text": "罗技激光无线游戏鼠标",
  "analyzer": "ik_smart"
}

再次运行分词,就能看到中文分词效果了

IK分词插件

上面已经完成了中文分词插件的安装

但是只使用了一个ik_smart的分词器

实际上插件还包含其他的分词器,他们有不同的特征

### 分词功能测试
POST http://localhost:9200/_analyze
Content-Type: application/json

{
  "text": "北京举行了冬季奥林匹克运动会",
  "analyzer": "ik_max_word"
}
### 分词功能测试
POST http://localhost:9200/_analyze
Content-Type: application/json

{
  "text": "北京举行了冬季奥林匹克运动会",
  "analyzer": "ik_smart"
}

上面同样的中文文字片段不同的中文分词器分词结果不同

经过分析我们可以知

ik_max_word:会详细的将文字片段分词,已经分词过的内容可能继续分词

​ 分词详细,查全率高,但是占用空间大,查询速度慢

ik_smart:会粗略的将文字片段分词,已经分词过的内容不会再次分词

​ 分词粗略,查全率低,但是占用空间小,查询速度快

下面我们要对ES进行基本的增删改查操作

操作ES数据

要想操作ES,先了解ES保存数据的结构

在这里插入图片描述

  • ES软件可以创建多个index(索引),我们可以将它理解为数据库中表的概念

  • 一个索引中可以保存多个document(文档),每个文档相当与数据库表中的一行

  • 一个文档是表中的一行数据,可以理解为一个对象,一般可以表示为json格式,json格式中的每一个属性对应表中的一个列

同学们从发给大家的es文档中

逐行运行每个命令,体会es的功能和数据的变化

详见文档内容

随笔

有关关系型数据库的索引

mysql这样的关系型数据库在按id查询时速度非常快

如果不查询id而查询像姓名这样的列,在默认情况下,会引发全表搜索,会逐行比对和查询,查询效果非常差,效率低

针对这种情况,我们可以在Mysql数据库中创建"索引"

来提高查询速度

类似字典中的偏旁部首查询

再次按照姓名查询时,可以大幅提高查询速度

但是如果查询条件是前模糊的

就无法使用创建的索引,一定是按全表,逐行搜索,效率非常低

所以才会出现ES

炉爆炎炸

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值