1 Star 0 Fork 0

刈剑丶 / YiYou

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
Note.md 51.09 KB
一键复制 编辑 原始数据 按行查看 历史
刈剑丶 提交于 2020-12-28 11:00 . 开启分支

易悠商城项目文档

1. 项目开发流程


1.1 搭建项目环境

####1.1.1搭建后台环境

  • 搭建父工程,开启项目,统一依赖管理,SpringBoot父工程
  • 创建注册中心微服务:yiyou-registry
  • 创建Zuul网关微服务:yiyou-gateway,拦截并分发请求
  • 创建商品聚合微服务:yiyou-item
    • pom文件设置打包方式为pom:pom
    • 创建微服务:yiyou-item-interface,定义entity,mapper,exception,interface...
    • 创建微服务:yiyou-item-service,商品微服务
  • 创建工具微服务:yiyou-common:通用工具
  • 图片上传模块:yiyou-upload
  • Elasticsearch 搜索模块:yiyou-search
  • 用户信息模块: yiyou-user
    • 实体类和接口:yiyou-user-interface
    • 业务和服务: yiyou-user-service
  • 短信微服务:yiyou-sms (阿里大于)
  • jwt 授权中心模块:yiyou-authentication
    • 公共模块:yiyou-authentication-common
    • 服务模块:yiyou-authentication-service
  • 购物车服务:yiyou-cart

####1.1.2搭建后台管理前端

  • 了解并学习ES6和Vue.js/node.js/webpack/vue-router
  • 构建后台管理前端模块
  • 学习为主,使用已有的前端Vue工程导入项目
    • 执行npm install 下载node_module(组件)
    • npm start/npm run dev 启动项目
      • config.js:修改api网关路径
      • conf/index.js:修改前端访问路径和端口
      • build/webpack.dev.config.js:禁用ip检查,负责处理局部组件

####1.1.3通过域名访问

  • 修改host文件(或者使用自己购买的域名指向本机ip,创建二级域名)
  • 下载nginx,修改配置文件,实现域名路由到不同的地址+端口
  • 解决跨域问题:CorsConfig配置类(在网关模块中处理)
  • 对接前端,实现数据展示
  • 分类查询,品牌查询,了解自定义组件的使用,前端Vuetify了解

1.2 后台功能实现

####1.2.1后台管理前端功能实现

  • 分类查询
  • 品牌查询,增加,修改,logo上传

####1.2.2文件上传

  • 找到并使用自定义组件vUpload
  • 后台编写控制器,处理文件上传(因为存在带宽限制,高并发的情况,所以需要单独创建一个微服务yiyou-upload)
  • 实现文件上传
    public String uploadImage(MultipartFile file) {
            //获取文件名
            String originalFilename = file.getOriginalFilename();
            //1.校验文件类型
            String contentType = file.getContentType();
            if (!CONTENT_TYPES.contains(contentType)) {
                //打印日志,记录错误信息
                LOGGER.info("文件类型不合法:{}", originalFilename);
                return null;
            }
            //2.校验文件内容
            try {
                BufferedImage bufferedImage = ImageIO.read(file.getInputStream());//返回一个二进制图片
                if (bufferedImage == null) {
                    LOGGER.info("文件内容不合法:{}", originalFilename);
                    return null;
                }
                //3.保存到服务器
                file.transferTo(new File("E:\\IDEA_workspace\\MyProject\\YiYouStore\\image\\" + originalFilename));
    
                return "http://image.yiyou.com/" + originalFilename; //返回图片路径
            } catch (IOException e) {
                LOGGER.info("服务器内部错误:{}", originalFilename);
                e.printStackTrace();
            }
            //4.返回url,进行回显
                //方法一:使用nginx代理图片路径
                //1.修改config:添加server配置,修改映射:image.yiyou.com,设置root 为文件存储路径
                //2.添加host:127.0.0.1 image.yiyou.com
                //3.reload nginx,通过http://image.yiyou.com/图片.jpg 访问图片
    
            //方法二:使用fastDFS回显图片路径
    
            return null;
        }
  • 图片显示,返回url路径
    • Nginx配置访问方式

    • 如何绕过网关?

      • 上传图片时由于有网关的存在,需要发送两次请求(一次请求测试),浪费性能,所以需要考虑绕过网关上传图片
      • 先将网关的路由取消,在前往配置nginx映射,顺序很重要,需要优先过滤文件请求
          location /api/upload {	
          			proxy_pass http://127.0.0.1:8082;
          			proxy_connect_timeout 600;
          			proxy_read_timeout 600;
          			#rewrite "用来匹配路径的正则" 重写后的路径 [指令];
          			rewrite "^/api/(.*)$" /$1 break; 
                  }

####1.2.3通过FastDFS改造文件上传流程

  • 引入依赖,添加配置,踪迹服务器地址

  • java配置:FastClientImport 配置类

  • 了解Linux,基于Linux配置FastDFS -基于Linux的Nginx服务器,实现图片访问的路径转发 -测试FastDFS官网的java测试,实现分布式文件系统 -整合FastDFS,整合FastDFS图片上传

  • FastFileStorageClient:文件存储客户端

    • 用法查看FastDfsTest类
    • FastFileStorageClient.uploadFile(文件流,文件大小,文件后缀,null);返回StorePath
    • StorePath:带分组和不带分组的路径

####1.2.4 商品信息管理(spu,sku)

  • 商品规格及参数

    • 参数组(spec_group):一对多参数
    • 参数表(spec_param):generic(是否是通用属性), searching(是否是搜索字段)
  • 商品列表数据模型及展示

    • Spu:Standard Product Unit (标准产品单位) ,一组具有共同属性的商品集
      • generic_spec:通用规格参数(id,value)
      • special_spec:特殊规格参数(id,[value数组]);
    • Sku:Stock Keeping Unit(库存量单位),SPU商品集因具体特性不同而细分的每个商品
      • indexes:0_0_0,具体的参数下标
      • own_spec:具体的值
      • stock:库存
    • 数据模型设计
  • 商品查询(GoodsService)

    • 初始化数据:根据cid查询品牌及规格参数
    • 添加查询条件:不同的orm框架有不同的添加方法,视情况而定
    • 添加过滤条件:通用mapper使用example,Criteria
    • 添加分页:PageHelper.startPage(page, rows);(pageHelper)
    • 执行查询,获取spu
    • List --> List 集合转换(lists.stream().map();)
    • PageInfo pageInfo = new PageInfo(spus);
    • new PageResult(pageInfo.getTotal(),spuBos);返回分页结果集
  • 商品编辑

    • 回显:根据spuid查询skus,spuDetail
    • 先删除stock后sku,再重新添加数据
    • 更新spu和spuDetail
    • 前端:待研究
  • 商品删除/商品上下架

    • 更新逻辑删除字段和上下架字段即可

1.3 搭建门户系统(yiyou-portal)

  • Live-Server :带有热加载功能的小型开发服务器

    • 安装(全局安装):npm install -g live-server
    • 运行:live-server
    • 指定端口运行:live-server --port=10002
    • 配置hosts,nginx配置,实现使用域名访问(www.yiyou.com)
    • common.js:自定义公用方法
      • getUrlParam():获取地址栏参数
      • formatPrice():格式化价格
      • formatDate():格式化事件
      • stringify():json对象转字符串
      • parse();字符串转json对象
  • 安装Elasticsearch: 数据分析引擎

  • 安装Kibana:提供了操作Elasticsearch索引数据的控制台

  • 安装ik分词器:是将一串字符串改为“词”的列表,最小单位的词

1.4 搭建搜索微服务

  • 创建搜索微服务

    • 新建yiyou-search模块
    • 添加配置信息,配置远程Elasticsearch
      • 添加Feign,实现负载均衡,熔断,发送请求
      • spring:
             application:
               name: search-service
             data:
               elasticsearch:
                 cluster-name: elasticsearch
                 cluster-nodes: 192.168.235.129:9300
    • 添加启动类,注册微服务:search-service
    • 引入item-interface,item-common模块
      • 在item-interface模块中新增api类,方便在其他模块中调用本模块的api接口
    • search微服务创建FeignClient接口,继承对应的api,用于请求其他微服务
  • 完成数据导入

    • 创建Spu转goods的service
    • 创建repository接口继承ElasticsearchRepository接口,用于使用elasticsearch的方法
    • 创建Test类,用于对数据进行导入:查询商品数据,导入到Elasticsearch中
    • 索引库为goods
    • 核心代码:GoodsService/ElasticsearchTest
    • 数据导入只需要一次,后续的数据导入将交由程序解决
  • 注意事项

    • spu参数问题:必须保证所有的参数都是优质的,否则在导入数据的时候会出现空指针的问题
    • 请求问题:在Feign发送请求的时候.如果发送的参数没有天机@RequestParam注解.则会导致发送的请求异常(发送post请求)
    • 远程请求问题:注意控制器是否有@RequestMapping("")的前置请求,有则要在Api中提前添加对应前置请求
  • 搭建流程

    • 聚合Api
      • NativeSearchBuilder:
      • StringTerms,InternalAvg:
      • AggregationBuilder:
      • AggregatedPage:
    • 构建索引数据结构Goods
    • 添加client接口
      • 添加Feign依赖
      • 创建接口继承Api
      • 添加注解:@FeignClient,启动类注解:@EnableFeignClients(可以添加熔断方法)
      • 配置相关参数,网关添加对应路由
    • 通过spu构造goods对象
    • 导入数据
    • 基本查询
      • NativeSearchQueryBuilder
      • QueryBuilders.matchQuery("all", searchParams.getKey()).operator(Operator.AND)
      • PageRequest
      • FetchSourceFilter:限制查询字段
  • 搭建技巧?

    • 在分模块写功能的情况下,如何使用其他模块的控制层接口?
      • 在需要使用的模块中添加一个Api接口,将控制器中的所有请求处理都放到该api接口中
      • 在调用该api的时候只需要使用FeignClient继承该接口即可使用其他开发者的模块的接口请求
      • 同时还解决了代码冗余的问题
    • ResponseEntity返回的结果需要经过解析,直接返回对象则不附带其他数据(响应码...)
  • 总结:

    • 基本搜索
      • 页面渲染
      • 分页
    • 分类和品牌的聚合
    • 对规格参数的聚合
    • 规格参数的页面渲染
    • 规格参数的过滤

1.5 搭建商品详情微服务

  • 搭建商品详情微服务:yiyou-goodsweb
    • Feign,Web以及自定义模块
    • 引入Thymeleaf模板引擎
      • 基础语法学习与使用:
      • 关闭thymeleaf缓存:spring.thymeleaf.cache=false 更新后ctrl+shift+F9 重载模板
      • 模板语法:获取后台传递的数据(非异步:model/ModelAndView)
          <script th:inline="javascript">
             	const a = /*[[${groups}]]*/ [];//可在js中使用
          </script>
      - th:text /th:utext th:each   ${}  
  • 将门户(yiyou-portal)中的item.html界面复制到resource/templates 目录下
    • 修改nginx.conf ,添加针对详情(item的路由请求):添加 /item 路由到8084端口
    • 由于静态资源的请求未进行路由(item),自动转到10002端口,访问门户网站,获取到静态资源(css,js)
  • 渲染商品详情页
    • spu brand skus spuDetail groups paramMap:{id,name} List<Map<String,Object>> categries
    • 后台返回Map数据集合,前台通过thymeleaf模板接收数据针对数据进行展示
      • vue与thymeleaf选择使用,实现数据展示

1.6 页面静态化

  • 使用TemplateEngine 模板引擎生成静态化页面

    • engine.process("item",context,printWriter);
    • 参数说明:模板页面,上下文(模型数据),io流写入静态文件
    • 生成的文件为与 html文件下
  • 修改nginx配置,代理静态页面

    • 新增 root html 路由本地静态页面

    • 先找本地

      root html; if (!-f $request_filename) { #请求的文件不存在,就反向代理 proxy_pass http://127.0.0.1:8084; break; }

  • 避免线程阻塞,使用线程池技术,多线程写入静态页面

    • public class ThreadUtils {
             private static final ExecutorService es = Executors.newFixedThreadPool(10);
             public static void execute(Runnable runnable) {
                 es.submit(runnable);
             }
       }
       /**
       * 新建线程处理页面静态化
       * @param spuId
       */
      public void asyncExcute(Long spuId) {
          ThreadUtils.execute(()->createHtml(spuId));
          /*ThreadUtils.execute(new Runnable() {
              @Override
              public void run() {
                  createHtml(spuId);
              }
          });*/
      }

1.7 用户注册

1.7.1 创建用户中心

  • 执行聚合,创建YiYou-user 父工程
    • leyou-user-interface:实体及接口
    • leyou-user-service:业务和服务

1.7.2 数据校验

  • 根据接口文档开发

1.8 阿里大于短信服务

  • 接入阿里短信服务

1.9 无状态登录

  • 有状态:在服务器端保存session
  • 无状态:不需要session,把登录状态保存在cookie中

1.9.1 jwt+rsa 服务鉴权

  • token:登陆时经常使用, 类型: jwt outh2 也可以自己设置
  • jwt
    • 头信息:jwt
    • 载荷:用户信息
    • 签发人,签发时间,有效时间
    • 签名:头信息+载荷,通过加密算法生成
      • 作用:校验 头信息和载荷内容的合法性

1.9.2 zuul网关访问流程

60397507329

1.9.3 搭建授权中心

  • 聚合工程:yiyou-authentication(common,serivce)

1.9.4 JwtUtils

  • 根据载荷还有私钥生成jwt类型的token
  • 根据公钥解析jwt类型的token,获取载荷信息(userInfo)
  • RsaUtils:生成公钥和私钥文件,并且读取公钥he私钥文件,并且返回公钥he私钥对象

1.9.5 登录功能

  • 调用UserSerivice中的queryUser接口,验证用户信息是否正确
  • 判断返回的用户信息是否为空
  • 不为空则生成jwt类型的token
  • 将token信息设置到cookie中:CookieUtils设置

1.9.6 首页用户名回显

  • 获取Cookie中的jwt类型的cookie:@CookieValue("Yy_Token")String token;
  • JwtUtils解析jwt token 获取用户信息(null则直接返回不响应)
  • 刷新cookie,jwt的时间
  • 响应用户信息

1.9.7 在zuul网关添加过滤器

  • 继承ZuulFilter实现过滤器
  • 获取Zuul的上下文对象(RequestContext),获取Request对象(context.getRequest())
  • 通过CookieUtils获取token,解析token
  • 白名单

1.10 搭建购物车

2. 知识点学习


2.1 ES6学习

  • var,let,const的区别
    • var :当前方法内有效,定义在循环中依旧属于方法级变量,可在for之外使用,作用域不合理
    • let:声明局部变量,作用域类似java,作用域与定义的位置相同,不会出现作用域越界的问题
    • const:声明常量,不可修改
  • 字符串拓展
    • includes():返回布尔值,表示是否找到参数字符串
    • startsWith():返回布尔值,表示参数字符串是否在原字符串的头部
    • endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部
    • 字符串模板
      • 使用``,声明字符串,自动格式化,无需换行,用于拼接字符串
      • 无论添加什么,都会变成字符串
    • 解构表达式
      • 数组解构
        • 声明数组:let arr = [10,20,30];
        • 解构数组:let [x,y,z] = arr;需要对应参数数量
        • 直接而读取变量: console.log(x);
      • 解构对象
        • 声明对象:let person = {name:'张三',age:'15'};
        • 解构对象:let {name,age}=person; 参数名必须和对象的参数一致,但是数量无所谓
          • let {name:映射别名,age:aaa}=person;
        • 直接而读取变量: console.log(name/别名);
        • const {categories, letter, ...params} = this.brand;解构部分参数,神域参数放到params中
    • 前台传递数组,集合时,使用 逗号(,)分隔,传递字符串,后台使用List ids 接收即可,传递参数:ids=1,2,3,4..
  • 函数优化
    • param = param || 1;判断param是否为空,为空则等于1(不是es6)
    • function( a , b = 1 ){} --- 1是默认值,在不传递形参的情况下
    • 箭头函数
      • java中lambda表达式写法:(参数列表)->{业务逻辑}
      • js写法:()=>{}
        • 业务逻辑简单(一行代码)可以直接省略{}
          • let fun = (x,y)=> x-y; 返回值为x-y
        • 参数只有一个时,()也可以省略
    • 对象函数属性简写
     let person = {
         name: "jack",
         // 以前:
         eat: function (food) {
             console.log(this.name + "在吃" + food);
         },
         // 箭头函数版:
         eat2: food => console.log(person.name + "在吃" + food),// 这里拿不到this
         // 简写版:
         eat3(food){
             console.log(this.name + "在吃" + food);
         }
     }
    • 箭头函数结合解构表达式
      • var hi = ({name}) => console.log("hello," + name);//单独取出对象的某条属性
  • map和reduce
    • map():接收一个函数,将原数组中的所有元素用这个函数处理后放入新数组返回
      • 有一个字符串数组,我们希望转为int数组:let arr = ['1','20','-5','3'];
      • 通过map转换为int数组:arr = arr.map(s => parseInt(s));
    • reduce():接收一个函数(必须)和一个初始值(可选),该函数接收两个参数:类似递归,知道使用完数组中的值
      • 第一个参数是上一次reduce处理的结果
      • 第二个参数是数组中要处理的下一个元素
      • reduce()会从左到右依次把数组中的元素用reduce处理,并把处理的结果作为下次reduce的第一个参数。如果是第一次, 会把前两个元素作为计算参数,或者把用户指定的初始值作为起始参数
  • 对象拓展
    • keys(obj):获取对象的所有key形成的数组
    • values(obj):获取对象的所有value形成的数组
    • entries(obj):获取对象的所有key和value形成的二维数组。格式:[[k1,v1],[k2,v2],...]
    • assian(dest, ...src) :将多个src对象的值 拷贝到 dest中(浅拷贝)。
  • 数组拓展
    • find(callback):把数组中的元素逐个传递给函数callback执行,如果返回true,则返回该元素
    • findIndex(callback):与find类似,不过返回的是品牌到的元素的索引
    • includes(callback):与find类似,如果匹配到元素,则返回true,代表找到了。

2.2 Vue学习

  • 安装Node.js

    • 安装nrm:npm install nrm -g
    • nrm ls 查看镜像 , nrm test 测试延迟, nrm use taobao 使用镜像
  • 安装Vue.js

    • npm init -y 初始化项目环境
    • 安装Vue,输入命令:npm install vue --save
    • node_modules是通过npm安装的所有模块的默认位置。
  • 使用Vue

    • vue基本结构
      <div id="app">
              容器
      </div>
      <script>
          // 创建vue实例
          let app = new Vue({
              el:"#app",  // el即element,该vue实例要渲染的页面元素
               data:{     // 渲染页面需要的数据
                          name: "",
               },
               methods:{
                  incr(){//可以获取this,简单的箭头函数
                  }
              }, //函数
               watch:{
                  name(newVal, oldVal){ }   //监听属性的变化
               },   //属性监听(方法名和监听的属性相同)
               created:{}, //钩子函数:vue实例创建时自动调用的方法
               components:{},//组件
               computed:{},//定义计算属性,计算本质就是方法,但是方法必须you返回值,使用方法类似数据模型,依赖项未改变,则从缓存中获取并计算
          });
      
      </script>
    • vue基本指令
      • v-model:双向数据绑定,常用与输入组件
      • v-on/@ :事件
        • @click 普通事件
        • @contextMenu:右击事件
          • 事件修饰符:prevent:阻止默认事件
        • @keyup:键盘事件
          • 13或enter:回车事件 @keyup.13=""
          • 组合事件:@keyup.ctrl.13=""
      • v-text/v-html:文本或html渲染
      • v-for:遍历,注意key的使用
        • 数组:v-for="(item,index) in items" key="index"
        • 对象:v-for="(value,key,index) in items" key="index"
      • v-if:不渲染
      • v-show:渲染后隐藏
      • v-bind/(:):绑定属性,动态传值
  • Vue组件化

    • 全局组件
      • 定义全局组件,两个参数:1,组件名称。2,组件参数
            Vue.component("counter",{
                    //模板组件必须有且只能有一个根节点,可是使用 ``来创建模型
                    template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>',
                    data(){  //data必须是一个函数,不再是一个对象。
                        return {
                            count:0
                        }
                    }  //不同于普通组件,需要使用方法且使用方法的方绘制作为数据模型
            })
      • 定义好的组件,可以任意复用多次
    • 局部组件
        <div id="app">
               <counter></counter>
               <!--  由于html是大小写不敏感的,如果采用上面的写法,则被认为是<loginform></loginform>
                        所以,如果是驼峰形式的组件,需要把驼峰转化为“-”的形式-->
        </div>
        <script>
            const counter = {
                template:'<button v-on:click="count++">你点了我 {{ count }} 次,我记住了.</button>',
                data(){
                    return {
                        count:0
                    }
                }
            };
            var app = new Vue({
                el:"#app",
                components:{
                    counter:counter // 将定义的对象注册为组件,同名可以省略只写一个
                }
            })
        </script>   
    • 组件通信
      • props(父向子传递)
        • 父组件使用子组件时,自定义属性(属性名任意,属性值为要传递的数据)
        • 子组件通过props接收父组件属性
        • vue提供了一个内置的this.$emit()函数,用来调用父组件绑定的函数
        • 子组件接收父组件的num属性:在data中定义同名属性接收
        • 子组件定义点击按钮,点击后对num进行加或减操作
  • 路由vue-router

    • 编写基础组件:index.html/login.js/reg.js,父组件调用注册登录组件
    • 安装vue-router
      • npm install vue-router --save
      • 引入:<script src="../node_modules/vue-router/dist/vue-router.js"></script>
    • 快速使用
      • 新建vue-router对象,并且指定路由规则:
      • routes:路由规则的数组,可以指定多个对象,每个对象是一条路由规则,包含以下属性:
        • path:路由的路径
        • component:组件名称
      • 在父组件中引入router对象:
    • router-link来指定跳转的路径
      • 登录
    • vue-router的锚点:
    • 通过来指定一个锚点,当路由的路径匹配时,vue-router会自动把对应组件放到锚点位置进行渲染
    • 通过指定一个跳转链接,当点击时,会触发vue-router的路由功能,路径中的hash值会随之改变
  • webpack

    • 作用

      • 将许多碎小文件打包成一个整体,减少单页面内的衍生请求次数,提高网站效率。
      • 将ES6的高级语法进行转换编译,以兼容老版本的浏览器。
      • 将代码打包的同时进行混淆,提高代码的安全性。
    • 安装

      • webpack支持全局安装和本地安装,官方推荐是本地安装,我们按照官方的来。
      • 安装最新版本webpack,输入命令:npm install --save-dev webpack
      • webpack 4+ 版本,你还需要安装 CLI ,输入命令:npm install webpack webpack-cli --save-dev
    • 核心概念

      • 入口(entry) webpack打包的起点,可以有一个或多个,一般是js文件。webpack会从启点文件开始,寻找启点直接或间接依赖的其它所有的依赖,包括JS、CSS、图片资源等,作为将来打包的原始数据
      • 输出(output) 出口一般包含两个属性:path和filename。用来告诉webpack打包的目标文件夹,以及文件的名称。目的地也可以有多个。
      • 加载器(loader) webpack本身只识别Js文件,如果要加载非JS文件,必须指定一些额外的加载器(loader),例如css-loader。然后将这些文件转为webpack能处理的有效模块,最后利用webpack的打包能力去处理。
      • 插件(plugins) 插件可以扩展webpack的功能,让webpack不仅仅是完成打包,甚至各种更复杂的功能,或者是对打包功能进行优化、压缩,提高效率。
    • 编写webpack配置

      • 项目根目录下创建webpack.config.js文件配置webpack(加载器和插件是可选的)
      • 入口entry
        • 创建 src/index.js,将index页面的js移动到该js
        • 使用es6手法:import导入js,模块
          • import Vue from '../node_modules/vue/dist/vue';
          • 子模块需要添加 export default loginForm; 导出模块
          • vue-router使用模块化加载后,必须增加一句:Vue.use(VueRouter)
        • module.exports={entry:'./src/index.js', //指定打包的入口文件 }
      • 出口output:就是输出的目的地。一般我们会用一个dist目录,作为打包输出的文件夹:
        module.exports={
            entry:'./src/main.js',  //指定打包的入口文件
            output:{
                // path: 输出的目录,__dirname是相对于webpack.config.js配置文件的绝对路径
                path : __dirname+'/dist',  
                filename:'build.js'	 //输出的js文件名
            }
        }

      = 执行打包:npx webpack --config webpack.config.js

      • 测试:引入生成的build.js文件(注意要在app容器之后引入),在需要使用组件的位置调用组件即可
    • 了解:

      • 打包css
      • 安装加载器
      • 配置启动命令
      • 打包HTML
      • 热更新的Web服务:
        • 安装插件:npm install webpack-dev-server --save-dev
        • 在package.json中配置script,添加启动配置
        • "dev": "webpack-dev-server --inline --hot --open --port 8080 --host 127.0.0.1"
          • inline:自动刷新
          • hot:热加载
          • port:指定端口
          • open:自动在默认浏览器打开
          • host:可以指定服务器的 ip,不指定则为127.0.0.1
        • 运行脚本:npm run dev
  • vue-cli脚手架

  • 安装:

    • 在开发中,需要打包的东西不止是js、css、html。还有更多的东西要处理,这些插件和加载器如果我们一一去添加就会比较麻烦。 幸好,vue官方提供了一个快速搭建vue项目的脚手架:vue-cli , 使用它能快速的构建一个web工程模板。
    • 安装命令:npm install -g vue-cli
  • 快速上手

    • 新建一个module:空模块,Terminal切换至该目录下
    • 用vue-cli命令,快速搭建一个webpack的项目:vue init webpack
    • 搭建完成后,使用npm run dev命令启动。
  • 项目结构:

    • 入口文件:main.js
    • 需要注意的是,我们看到有一类后缀名为.vue的文件,我们称为单文件组件,而单文件组件中包含三部分内容:
      • template:模板,支持html语法高亮和提示
      • script:js脚本,这里编写的就是vue的组件对象,还可以有data(){}等
      • style:样式,支持CSS语法高亮和提示
    • 每个组件都有自己独立的html、JS、CSS,互不干扰,真正做到可独立复用。
  • 运行

    • 查看生成的package.json:
    • 可以看到这引入了非常多的依赖,绝大多数都是开发期依赖,比如大量的加载器。
    • 运行时依赖只有vue和vue-router
    • 脚本有三个:
      • dev:使用了webpack-dev-server命令,开发时热部署使用
      • start:使用了npm run dev命令,与上面的dev效果完全一样,当脚本名为“start”时,可以省略“run”。
      • build:等同于webpack的打包功能,会打包到dist目录下。
    • 我们执行npm run dev 或者 npm start 都可以启动项目:

2.3 通用Mapper+PageHelper实现分页

  • 通用Mapper
    • 插入语句:都会将id主键返回到实体类中
      • insert();会设置所有字段,无则设为空
      • insertSelective();选择性拼接sql,拼接更少的字符串,效率高一些
    • $和#的区别:
      • ($):$传入的参数在SqL中直接显示为传入的值,$方式无法防止Sql注入
      • (#):#传入的参数在SQL中显示为字符串,#方式能够很大程度防止sql注入
      • 大多数情况下还是经常使用#,一般能用#的就别用$;但有些情况下必须使用$,
        • 例:MyBatis排序时使用order by 动态参数时需要注意,用$而不是#。
        • $方式一般用于传入数据库对象,例如传入表名。
  • PageHelp分页工具

2.4 Nginx WEB服务器 (网关)

  • 什么是Nginx?

    • Nginx是反向代理工具(反向代理服务器)
    • NIO:not-blocking-io: 同步非阻塞的I/O模型
    • BIO:blocking-IO :同步阻塞I/O模式
      • 同步与异步,阻塞与非阻塞。
    • AIO (Asynchronous I/O):异步非阻塞的IO模型
  • nginx可以作为web服务器,但更多的时候,我们把它作为网关,因为它具备网关必备的功能:

    • 反向代理
    • 负载均衡
    • 动态路由
    • 请求过滤
  • nginx作为web服务器

    • Web服务器分2类:
      • web应用服务器,如:
        • tomcat
        • resin
        • jetty
      • web服务器,如:
        • Apache 服务器
        • Nginx
        • IIS
    • 区分:web服务器不能解析jsp等页面,只能处理js、css、html等静态资源。
    • 并发:web服务器的并发能力远高于web应用服务器。
    • Nginx + tomcat
  • nginx作为反向代理

    • 什么是反向代理?
      • 代理:通过客户机的配置,实现让一台服务器代理客户机,客户的所有请求都交给代理服务器处理。
      • 反向代理:用一台服务器,代理真实服务器,用户访问时,不再是访问真实服务器,而是代理服务器。
    • nginx可以当做反向代理服务器来使用:(利用反向代理,解决端口问题)
      • 我们需要提前在nginx中配置好反向代理的规则,不同的请求,交给不同的真实服务器处理
      • 当请求到达nginx,nginx会根据已经定义的规则进行请求的转发,从而实现路由功能
  • 使用

    • nginx可以通过命令行来启动,操作命令:
      • 启动:start nginx.exe
      • 停止:nginx.exe -s stop
      • 重新加载:nginx.exe -s reload
    • 反向代理配置:配置nginx/conf/nginx.conf文件
      • nginx中的每个server就是一个反向代理配置,可以有多个server
      • 添加Server,配置如下
          server {
                  listen       80;    #箭筒端口
                  server_name  manage.yiyou.com;  #映射网址
          
                  proxy_set_header X-Forwarded-Host $host;
                  proxy_set_header X-Forwarded-Server $host;
                  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          
                  location / {
          			proxy_pass http://127.0.0.1:9001;   #对应路径
          			proxy_connect_timeout 600;          #连接超时时间
          			proxy_read_timeout 600;             #读取超时时间
                      
                      #当配置图片(本地指定文件路径时) 
                      
                  }
              }

2.5 FastDFS 分布式文件系统 (GFS,HDFS,TFS)

  • 安装FastDFS

    • FastDFS
      • 前往gitee根据FastDFS项目需求,下载所需的文件,以及Linux版nginx服务器 安装虚拟机,添加Linux虚拟系统(使用Nat网络适配),开始着手安装(可以参考官方安装文档)
        • 查看虚拟机ip地址:
        • 安装gcc(用于编译c语言): yum install gcc -y
        • rm -f /var/run/yum.pid 解除yum命令占用问题
        • 安装unzip(zip解压命令): yum install unzip zip -y [ 默认已安装 ]
          • zip解压: unzip 文件名.zip
          • tar.gz : tar -zxvf 文件名.tar.gz
        • 安装 libevent(插件): yum install libevent -y [ 默认已安装 ]
        • 安装libfatscommon:
          • 解压后进入该目录
          • 执行命令: ./make.sh && ./make.sh install #编译安装
        • 安装FastDFS
          • 解压后进入该目录
          • 执行命令: ./make.sh && ./make.sh install #编译安装
          • 执行命令: ll /etc/init.d/ | grep fdfs #查看脚本文件
          • 执行命令: ll /etc/fdfs/ #安装成功就会看到配置文件模板
        • 启动服务
          • 先处理防火墙

            • 不关闭防火墙的话无法使用
            • systemctl stop firewalld.service #关闭
            • systemctl restart firewalld.service #重启
          • 启动服务

            • 修改配置文件设置自己的路径,先复制模板文件,删除simple后缀,编辑.conf文件
            • vim 或通过虚拟机编辑配置文件,设置base_path路径
            • service fdfs_trackerd start # 启用服务
            • service fdfs_storaged start # 启用服务
            • ps -ef | grep fdfs_trackerd #检查是否启动成功
            • chkconfig fdfs_trackerd on #设置服务开机启动
            • chkconfig fdfs_storaged on #设置服务开机启动
            • ps -ef | grep fdfs #查看全部fastdfs的服务
            • netstat -unltp|grep fdfs 查看端口
          • 安装FastDFS-nginx-module

            • 解压
            • 修改config,进入src,编辑config文件
            • 修改 /usr/local/ 统一删除local
            • 配置 nginx与fastdfs关联配置文件
              • 复制配置文件modul_fastdfs.conf 到/etc/fdfs/文件下
              • 编辑该文件,配置连接超时(connect_timeout),tracker访问地址和端口(tracker_server)
              • 开启访问组名(url_have_group_name),设置文件存储路径(srote_path0)
              • 复制fastdfs部分配置文件(http.conf,mime.types)到 /etc/fdfs/ 文件下
          • 安装nginx

            • 安装ngnix的依赖库
            • yum install git gcc gcc-c++ make automake autoconf libtool pcre pcre-devel zlib zlib-devel openssl-devel wget vim -y
            • 解压nginx压缩包,进入该目录
            • 配置nginx安装包,并制指定fastdfs-nginx-module
            • ./configure --add-module=/usr/local/yiyou/fastdfs-nginx-module/src/ 
            • 编译并安装 make && make install
        • 配置nginx访问
        server {
                 listen       80;    ## 该端口为storage.conf中的http.server_port相同
                 server_name  192.168.11.133;  #服务器端口(image.yiyou.com)
                 location ~/group[0-9]/ {
                 ngx_fastdfs_module;
                 }
                 error_page   500 502 503 504  /50x.html;
                 location = /50x.html {
                 root   html;
                 }
             }
        • 启动 nginx
        • /usr/local/nginx/sbin/nginx #启动nginx
        • /usr/local/nginx/sbin/nginx -s reload #重启nginx
        • /usr/local/nginx/sbin/nginx -s stop #停止nginx
        • 配置脚本实现开机自启nginx(查看网上资料),修改部分路径即可
  • FastDFS Client 客户端

    • 引入依赖: 依赖管理:<fastDFS.client.version>1.26.2</fastDFS.client.version>
       <dependency>
           <groupId>com.github.tobato</groupId>
           <artifactId>fastdfs-client</artifactId>
       </dependency>
    • 配置FastDFS
    fdfs:
      so-timeout: 1501      #超时时间
      connect-timeout: 601  #连接超时时间
      thumb-image: # 缩略图
        width: 60
        height: 60
        tracker-list: # tracker地址
          - 192.168.11.132:22122

2.6 Elasticsearch数据分析引擎

  • 分布式全文检索技术:restful接口

  • Elasticsearch: 数据分析引擎

    • 安装到Linux,模拟生产环境
      • 出于安全考虑,elasticsearch默认不允许以root账号运行。
      • 创建新用户:useradd yiyou (自动在home文件下创建新用户文件夹)
      • 设置用户密码: passwd yiyou (550098879)
      • 切换用户: su - yiyou
      • 退出用户: exit
    • 上传Elasticsearch至新用户文件夹下
      • 设置文件权限(回到root用户下:exit)
        • 进入新用户文件目录下: cd /home/yiyou
        • 修改文件所属(用户:组): chown yiyou:yiyou elasticsearch-6.3.0.tar.gz
        • 修改文件权限: chmod 755 elasticsearch-6.3.0.tar.gz
      • 解压文件:tag -zxvf elasticsearch-6.3.0.tar.gz
      • 重命名文件: mv elasticsearch-6.3.0.tar.gz elasticsearch
    • 权限授予:chown -R yiyou:yiyou /home/yiyou/elasticsearch
    • 启动: bin/elasticsearch -d 后代启动
  • 安装Kibana

    • 基于Node.js的Elasticsearch索引库数据统计工具,可以利用Elasticsearch的聚合功能,生成各种图表,如柱形图,线状图,饼图等。
    • 提供了操作Elasticsearch索引数据的控制台,并且提供了一定的API提示,非常有利于我们学习Elasticsearch的语法。
    • 安装Kibana:需要Node.js的环境,所以安装到windows中
  • 安装ik分词器

    • 是将一串字符串改为“词”的列表,最小单位的词
    • 解压到Elasticsearch目录的plugins目录中,解压完成后删除压缩包,防止异常
    • unzip elasticsearch-analysis-ik-6.3.0.zip -d ik-analyzer
    • 重启Elasticsearch
  • 解决一系列启动异常后,启动elasticsearch,通过http://192.168.235.129:9200访问成功即可

  • 通过kibana提供( http://localhost:5601/)的控制台工具,实现对数据的增删改查

  • Elasticsearch的基本概念

    • 索引(indices)---------------------Databases 数据库

      • 创建索引
      • 删除索引
    • 类型(type)-------------------------Table 数据表

    • 文档(Document)----------------Row 行

    • 字段(Field)-------------------Columns 列

  • 映射配置

    • 创建映射字段
    • 查看映射关系
    • 字段属性详解
      • _source:源文档信息,所有的数据都在里面。
      • _id:这条文档的唯一标示,与文档自己的id字段没有关联
  • Elasticsearch的基础操作

    • 新增
    • 修改
    • 删除
    • 查询
      • 全部查询
      • 匹配查询
      • 多字段查询
      • 词条匹配
      • 多次条精确匹配
    • 结果过滤
      • 直接指定字段(展示):"_source": ["title","price"],
      • 指定includes和excludes
        • includes:来指定想要显示的字段
        • excludes:来指定不想要显示的字段
        • "_source": {"includes":{} , "excludes":{}},
    • 高级查询
      • 布尔组合(bool)
      • 范围查询(tange)
      • 模糊查询(fuzzy)
    • 过滤(filter)
      • 条件查询中进行过滤
      • 无查询条件,直接过滤
    • 排序
      • 单字段排序
      • 多字段排序
    • 聚合aggregations
      • Elasticsearch中的聚合,包含多种类型,最常用的两种,一个叫,一个叫度量
      • 桶(bucket):根据不同的类型划分桶
      • 度量(metrics):对数据进行运算
      • 聚合为桶:根据词条划分
      • 桶内度量:数据计算划分
      • 桶内嵌套桶:组中分组
      • 划分桶的其他方式
        • 阶梯分桶Histogram
        • 范围分桶range

###2.7 Spring Data Elasticsearch

  • 简介
    • Elasticsearch提供的Java客户端有一些不太方便的地方,这里就不讲解原生的Elasticsearch客户端API了。而是学习Spring提供的套件:Spring Data Elasticsearch。
    • Spring Data Elasticsearch是Spring Data项目下的一个子模块

2.8 RabbitMQ 消息队列

  • 基于AMQP协议,erlang语言开发,稳定性好
  • 基于AMQP的一款消息管理系统
  • 分类
    • MQ:消息队列
    • AMQP:协议 实现方式 任何语言 支持5中 rabbitMQ(erlang)
    • JMS: jdk 标准, java 只支持两种数据模型 RockerMQ ActivityMQ

2.8.1 Linux 安装

####2.8.2 RabbitMQ的基础使用

  • 生产者发送消息

  • 消费者获取消息

  • 消息确认机制(ACK)

    • 自动:自动确认消息,存在出现异常消息丢失的现象

    • 手动:手动确认消息,避免异常导致的消息丢失问题

    • 能者多劳:类似Feign的负载均衡

      • 告诉RabbitMQ一次不要向工作人员发送多于一条消息
        channel.basicQos(1);
  • 订阅模型分类

    • 解读:

      1、1个生产者,多个消费者

      2、每一个消费者都有自己的一个队列

      3、生产者没有将消息直接发送到队列,而是发送到了交换机

      4、每个队列都要绑定到交换机

      5、生产者发送的消息,经过交换机到达队列,实现一个消息被多个消费者获取的目的

      X(Exchanges):交换机一方面:接收生产者发送的消息。另一方面:知道如何处理消息,例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。

      Exchange类型有以下几种:

      Fanout:广播,将消息交给所有绑定到交换机的队列

      Direct:定向,把消息交给符合指定routing key 的队列

      Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列

      Exchange(交换机)只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失!

    • 订阅模型-Fanout(广播)

      • 将消息发送到交换机,由交换机将消息的发送给绑定了交换机的队列
      • 能者多劳(多消费者,一次只处理一个消息),避免消息拥堵,性能浪费
    • 订阅类型-Direct(路由模式)

      • 发送指定类型的消息:RoutingKey,通过RoutingKey进行匹配需要接受的消息

        •  channel.basicPublish(EXCHANGE_NAME, "insert", null, message.getBytes());
      • 处理指定类型的消息:设置可接受的类型

        •  channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "update");
      • 订阅模型-Topic(通配符)

        • 基于Direct模式,新增通配符匹配功能
        • item.update item.*
  • 持久化

    • 交换机持久化
    • 队列持久化
    • 消息持久化
  • 总结

    • 简单模型:生产者-->队列-->消费者
    • **工作模型:**生产者-->队列-->消费者(多)
    • 发布订阅之fanout:生产者-->交换机-->队列(多)-->消费者(多)
    • 发布订阅之direct:生产者-->交换机-->队列(多)-->消费者(多)
      • 指定RoutingKey:生产者和绑定交换机都需要指定
    • 发布订阅之topic:生产者-->交换机-->队列(多)-->消费者(多)
      • '*' :匹配一个词
      • '#' :匹配多个词
    • ACK确认机制:推荐手动
    • 能者多劳:性能高者多处理消息,避免消息堆积
    • 持久化

####2.8.3SpringAMQP

  • Spring-amqp是对AMQP协议的抽象实现,而spring-rabbit 是对协议的具体实现,也是目前的唯一实现。底层使用的就是RabbitMQ。

  • 依赖和配置

    spring.rabbitmq. host (地址) virtual-host(虚拟机) username password 交换机

  • 注解

	@RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = "leyou.create.web.queue",durable = "true"), //队列持久化
            exchange = @Exchange(
                    value = "leyou.item.exchange",
                    ignoreDeclarationExceptions = "true",
                    type = ExchangeTypes.TOPIC
            ),
            key = {"item.insert","item.update"}
    ))
    public void listenCreate(Long id) throws Exception{
        if (id == null){
            return;
        }
        //接收到消息后执行相关更新操作
    }
  • 发送消息和监听消息
    • 发送消息
      • 在编辑商品的时候,发送一个消息到队列中
      • 发送消息:AmqpTemplate.converAndSend();
    • 监听消息
      • 分别在搜索服务,item服务中添加监听,接收到消息则进行数据和静态页面的更新

2.9 Redis(Linux)安装与使用

  • 安装:详见csdn

  • RedisManager管理工具

  • SpringDataRedis

  • RedisTemplate

  • StringRedisTemplate : 避免字符串序列化的问题,浪费内存

  • 注意事项

    • redis 6.0+ 版本需要linux的gcc版本大于5.3版本
    • redis.conf 配置文件中,禁用中文注释
    • linux的home目录路径应替换为root : /root/MyFiles/Redis/redis/redis.conf

2.10 手机验证码流程

3. 常用工具类


3.1 数据类型工具类

  • StringUtils (lang3/spring)

    • 判断字符串状态:
    • 将集合拼接成字符串:StringUtils.join(list,"-");
    • 获取后缀:StringUtils.substringAfterLast(path,".");
  • CollectionUtils

    • 判断集合状态
  • ObjectUtils

  • BeanUtils: 实体类工具

    • 复制实体bean属性到另一个对象中:BeanUtils.copyProperties(spu,spuBo);//复制bean的属性
  • 集合转换

    • list.stream().map(category -> { return category.getName();}).collect(Collectors.toList());
    • 将对象集合转换为字符串集合,返回一个集合对象
  • jdk8新特性

  • ObjectMapper公路类

    • 将json格式转换成对象: MAPPER.readValue(detail.getGenericSpec(), new TypeReference<Map<String,Object>>(){});
    • 将对象转换成json字符串:MAPPER.writeValueAsString(skuMapList)

3.2 IO流工具类

  • ImageIO:
    • BufferedImage bufferedImage = ImageIO.read(inputStream);
    • 返回一个二进制图片,包含图片的基本属性(宽高..)
    • 判断bufferedImage,不为空则是图片,空则说明图片不合法

4. 项目异常处


4.1 环境配置异常

  • 父工程依赖管理出现未找到异常(报红)
    • 问题所在:依赖不曾导入过,仓库中无法找到,依赖管理不会直接导入依赖
    • 解决:先将依赖管理关闭,将依赖导入本地仓库即可,再进行依赖管理即可
  • SpringCloud : spring-boot-starter-actuator与datasource引起的循环依赖问题
    • 添加配置: spring.cloud.refresh.refreshable = none (自行转换成yml格式)
  • 跨域异常:
    • 跨域场景:协议不同,域名不同,端口不同,二级域名不同
    • 跨域前提:ajax请求才会出现跨域
    • 解决:
      • Cors:网关添加配置类,SpringMVC提供了CorsFilter类
        • 规范化的跨域请求解决方案,安全可靠。
        • 在服务端进行控制是否允许跨域,可自定义规则
        • 支持各种请求方式
      • 缺点:
        • 会产生额外的请求
      @Configuration
      public class GlobalCorsConfig {
          @Bean
          public CorsFilter corsFilter() {
              //1.添加CORS配置信息
              CorsConfiguration config = new CorsConfiguration();
              //1) 允许的域,不要写*,否则cookie就无法使用了
              config.addAllowedOrigin("http://manage.yiyou.com");
              //2) 是否发送Cookie信息
              config.setAllowCredentials(true);
              //3) 允许的请求方式
              config.addAllowedMethod("OPTIONS");
              config.addAllowedMethod("HEAD");
              config.addAllowedMethod("GET");
              config.addAllowedMethod("PUT");
              config.addAllowedMethod("POST");
              config.addAllowedMethod("DELETE");
              config.addAllowedMethod("PATCH");
              // 4)允许的头信息
              config.addAllowedHeader("*");
              //2.添加映射路径,我们拦截一切请求
              UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
              configSource.registerCorsConfiguration("/**", config);
              //3.返回新的CorsFilter.
              return new CorsFilter(configSource);
          }
      }
      • jsonp:利用script标签可以跨域的原理实现。 问题:需要服务的支持, 只能发起GET请求
      • nginx反向代理:利用nginx反向代理把跨域为不跨域,支持各种请求方式
        • 需要在nginx进行额外配置,语义不清晰
  • 父模块配置了数据库源,导致子模块启动要求配置数据源
    • 解决:
      • 配置相应参数,配置数据源即可
      • 启动类排除掉DataSourceAutoConfiguration(数据源自动配置)
              @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
              public class CosApplication {
                  public static void main(String[] args) {
                      SpringApplication.run(CosApplication.class);
                  }
              }
                         

5. 访问与部署

  • idea连接远程服务器

    • view->Tool windows->Remote host 打开远程服务器窗口
    • ...->选择SFTP添加一个远程服务器->编辑远程服务器进行连接
  • idea打开服务器命令栏

    • Tool->start ssh session->选择服务器即可
  • 本机模拟域名/二级域名访问网站

    • 修改hosts文件,添加本机ip映射网址:127.0.0.1 manage.yiyou.com
    • 前端vue工程修改:build/webpackage.dev.conf.js文件,devServer添加 disableHostCheck: true,//禁用ip地址检查
    • 通过该映射网址即可访问本机ip
  • 使用Feign发送请求的时候发送的请求变为post请求

    • 参数需要使用@RequestParam 注解声明参数,否则无法识别传递的参数
  • Spu的参数信息需要填写完善,否则会导致向Elasticsearch导入数据时出现空指针异常的问题 ​

  • 谷歌浏览器无法保存本地cookie的解决方法: 右键快捷方式->属性->快捷方式->目标->添加 --enable-file-cookies (注意空格区分)

6.Idea快捷操作

  • ctrl+alt+M:抽取代码生成方法
  • 快速捕获异常:ctrl+alt+t
  • debug
    • F7:进入方法
1
https://gitee.com/cutting_sword/YiYou.git
git@gitee.com:cutting_sword/YiYou.git
cutting_sword
YiYou
YiYou
master

搜索帮助