谷粒商城环境搭建

谷粒商城环境搭建

1.安装虚拟机virtualbox

virtualbox下载地址:https://mirror.tuna.tsinghua.edu.cn/help/virtualbox/
**步骤:
下载安装即可

2.安装vagrant

简介:vagrant可以根据镜像在virtualbox中快速创建虚拟机

vagrant下载地址:https://www.vagrantup.com/downloads.html
镜像仓库:https://app.vagrantup.com/boxes/search(可查看镜像名字)
中国镜像仓库:http://mirrors.ustc.edu.cn/centos-cloud/centos/6/vagrant/x86_64/images/
vagrant命令:https://www.jianshu.com/p/7e8f61376053
**步骤:
1.下载安装vagrant,cmd中输入vagrant -v查看是否安装成功
2.使用vagrant在virtualBox中安装linux虚拟机:
	方式1:
		初始化:vagrant init centos/7(根据镜像名字初始化,创建了一个vagrantfile文件)
	    启动:vagrant up(根据vagrantfile下载镜像,需要在有vagrantfile文件的目录下启动)
	    连接:vagrant ssh(whoami查看当前登录用户,exit退出连接)
	    关闭:在virtualbox中关闭虚拟机
	    再次启动:vagrant up
	    
	方式2:(推荐)
		访问中科大镜像网下载.box文件:http://mirrors.ustc.edu.cn/centos-cloud/centos
		根据box文件初始化centos7:vagrant box add centos7 CentOS-7-x86_64-Vagrant-2004_01.VirtualBox.box
		初始化:vagrant init centos7
		修改配置:编辑Vagrantfile文件,修改config.vm.box = "centos7"
		启动:vagrant up
		连接:vagrant ssh(可能出现vagrant@127.0.0.1: Permission denied (publickey,gssapi-keyex,gssapi-with-mic). 错误)
		异常解决:https://blog.csdn.net/ai_0922/article/details/106366521(权限问题)

2.1.配置虚拟网络

简介:
1.什么是端口转发:
	配置好虚拟机后,默认情况下使用的是端口转发如下图,例如虚拟机中有一个mysql服务,需要在virtualbox中设置端口映射windows本机端口(本机2222映射->虚拟机22),才可以在windows中ssh连接虚拟机(127.0.0.1 2222)
	缺点:需要配置很多映射端口
	解决:使用虚拟网卡给虚拟机配置一个ip,使本机和虚拟机可以ping通
	
2.配置虚拟网络:
	方法1:登录虚拟机,设置网卡
	方法2:修改vagrantfile配置文件(因为虚拟机是根据这个配置文件启动的)
		1.查看本机虚拟地址:ipconfig (192.168.56.1)
		2.打开配置文件修改地址:config.vm.network "private_network", ip: "192.168.56.10"
		3.重启vagrant reload(在virtualBox中重启无效)
		4.验证:ip addr,互相ping

端口转发:
在这里插入图片描述

本机虚拟地址:
在这里插入图片描述

2.2.Xshell连接虚拟机

1.连接:vagrant ssh
2.切换:su root(密码:vagrant)
3.修改允许密码连接
	vi /etc/ssh/sshd_config
		PasswordAuthentication yes
	i(编辑模式)
	esc
	:wq(保存退出)
	reboot
4.xshell连接 192.168.56.10
	账号密码:vagrant/vagrant
			root/vagrant
5.切换root:su root

2.3.配置网关、DNS

修改网卡相关信息

1.ip addr查看哪个网卡使用了192.168.56.10 ip
查看结果是enth1使用

2.修改配置
cd /etc/sysconfig/network-scripts/
vi ifcfg-eth1

增加以下三行:
GATEWAY=192.168.56.1
DNS1=114.114.114.114
DNS2=8.8.8.8

3.重启网卡
service network restart

2.4.配置yum源加速

1.备份原yum源
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup

2.使用新yum源
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo

3.生成缓存
yum makecache

4.安装
yum -y install wget
yum -y install unzip

3.安装docker

简介:
	虚拟化容器技术,docker基于镜像秒级启动各种容器,每一种容器都是一个完整的运行环境(每一个容器可以看做一个完整的linux环境),容器之间相互隔离。
	例如windows中的ghost,根据windwos镜像安装系统(镜像中可能包含其他软件,qq、wx)
	docker利用各种镜像在linux中安装容器(可以根据一个镜像安装多个容器),例如根据mysql镜像多个mysql容器
	docker build
	docker pull
	docker run

docker安装官方文档:https://docs.docker.com/engine/install/centos/(进入路径->developers->Docs->Guides->Get Docker->Docker for linux->Docker Engine->install->centOS )
镜像仓库:https://hub.docker.com

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-duRmcJug-1686883355978)(/1630247867023.png)]

**步骤:
1.Uninstall old versions(卸载旧版本):
 sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
2.Set up the repository(安装相关依赖):
 sudo yum install -y yum-utils

3.设置镜像地址(用于加速下载docker用,并非docker image镜像)
 sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
 异常:下载docker的镜像报错fastmirror
 解决:
 	vi /etc/yum/pluginconf.d/fastestmirror.conf(修改 enable=1 为 enable=0)
 	vi /etc/yum.conf(修改 plugins=1 为 plugins=0)
 	yum clean all
	rm -rf /var/cache/yum
	yum makecache

4.安装docker
sudo yum install -y docker-ce docker-ce-cli containerd.io

5、启动docker
设置开机自启:sudo systemctl enable docker
启动:sudo systemctl start docker

6、测试
docker -v

3.1.相关命令

1、查看已启动镜像:docker images
   查看已运行容器:docker ps
2、查看所有镜像:docker images -a
3、启动docker:sudo systemctl start docker
4、虚拟机开机启动:sudo systemctl enable docker
5、设置自动启动容器:sudo docker update mysql --restart=always
6、启动已存在的容器或重启容器,例:
	1)查看容器的id或name:docker ps -a
	2)重启restart id或name【重启就代表启动了】:
		docker restart 1b4671904bfa
		docker restart mysql
7、终止容器:docker stop redis
8、删除容器:docker rm redis
9、进入容器的运行时环境
进入mysql:docker exec -it mysql /bin/bash
进入redis:docker exec -it redis redis-cli
进入redis:docker exec -it redis /bin/sh
whereis mysql
10、退出容器运行时环境:exit
11、虚拟机开机自动启动mysql:sudo docker update mysql --restart=always

3.2.配置镜像加速器

作用:下载docker image镜像加速

1.登录阿里云:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
2.镜像加速器->centos(依次执行以下命令)
sudo mkdir -p /etc/docker

sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://xxxxxxx.mirror.aliyuncs.com"]
}
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker

3.3.拉取mysql镜像启动容器

简介:https://hub.docker.com 镜像仓库
	docker pull mysql:		拉取最新版本镜像
	docker pull mysql:5.7 	拉取指定版本镜像
    
navicat12安装:https://cloud.tencent.com/developer/article/1718099

由于找不到MSVCR120.dll,无法继续执行代码.重新安装程序可能会解决此问题:https://blog.csdn.net/burning1996/article/details/100315436
步骤:
1.拉取镜像:
sudu docker pull mysql:5.7

2.查看已拉取的镜像
docker images

3.启动一个容器
docker run -p 3306:3306 --name mysql \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/ib/mysql \
-v /mydata/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7

参数说明(下面提到的主机指的是虚拟机)
-p 3306:3306:将容器的3306端口映射到主机的3306端口
--name 当前启动的容器 设置名字
-v /mydata/mysql/conf:/etc/mysql:将配置文件夹挂载到主机
-v /mydata/mysql/log:/var/log/mysgl:将日志文件夹挂载到主机
-v /mydata/mysql/data:/var/ib/mysql/:将配置文件夹挂载到主机
-e MYSQL_ROOT_PASSWORD=root: 初始化root用户的密码
-d 后台启动
mysql:5.7: 该容器所使用的镜像

4、远程无法连接mysql【没有修改远程授权】https://blog.csdn.net/scarecrow__/article/details/81556845
	解决:进入容器连接mysql修改授权
	1)进入mysql容器:docker exec -it mysql /bin/bash
	2)连入mysql:mysql -uroot -proot
	3)查询:select host,user,plugin,authentication_string from mysql.user;
		找到user为root的两列,
			%:表示不限制ip的配置
			localhost:表示本地连接的配置
			plugin数据非mysql_native_password表示要修改密码
		执行以下语句:
		ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root';

5、远程无法连接mysql:修改root用户远程访问权限
	“password”填写密码 root
grant all privileges on *.* to root@"%" identified by "password" with grant option;

6、修改mysql字符集
vi /mydata/mysql/conf/my.cnf
[client]
default-character-set=utf8

[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve

7、重启:docker restart mysql

8、虚拟机开机自动启动mysql容器
	sudo docker update mysql --restart=always

正确授权配置:
在这里插入图片描述

3.4.拉取redis镜像启动容器

简介:
1.redis配置文件:https://raw.githubusercontent.com/redis/redis/6.0/redis.conf
步骤:
1.拉取镜像:docker pull redis

2.坑:使用-v命令挂载时,主机会把redis.conf当做目录创建,所以先将改文件创建好
mkdir -p /mydata/redis/conf
touch /mydata/redis/conf/redis.conf
开启redis持久化:
vi /mydata/redis/conf/redis.conf
	appendonly yes

3.启动容器
docker run -p 6379:6379 --name redis \
-v /mydata/redis/data:/data \
-v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf
参数说明:
redis-server /etc/redis/redis.conf:该容器redis-server使用/etc/redis/redis.conf配置文件启动

4、自启动:sudo docker update redis --restart=always
docker restart redis

5、终止容器:docker stop redis
   删除容器:docker rm redis

6、连接redis:
	1)进入容器内部连接:
	docker exec -it redis /bin/bash
	redis-cli -p 6379
	2)使用客户端连接:
	docker exec -it redis redis-cli 
	3)外部windows可视化客户端连接6379端口

3.5.安装nps(内网穿透服务端)

https://ehang-io.github.io/nps
注意:
	1.有云服务器且需要用到内网穿透的安装,有很多其他方案代替,例如花生壳
	2.服务端需要安装在外网云服务器上

步骤:
1.拉取镜像
docker pull ffdfgdfg/nps

2.下载conf配置文件
https://hub.docker.com/r/ffdfgdfg/nps

3.conf文件夹移动到/mydata/nps

4.启动容器(以host模式启动,自动映射端口)
docker run -d --name nps --net=host \
-v /mydata/nps/conf:/conf ffdfgdfg/nps

5.自启动
sudo docker update nps --restart=always

6.重启
docker restart nps

在这里插入图片描述

3.6.安装npc(内网穿透客户端)

https://ehang-io.github.io/nps
注意:客户端需要安装在本地虚拟机环境

docker run -d --name npc --net=host \
-v /mydata/npc/conf:/conf \
ffdfgdfg/npc -server=<ip:port> -vkey=<密钥> -type=tcp


1.docker pull ffdfgdfg/npc

2.下载conf文件夹并解压,或前往项目主页自行下载(升级请忽略)
https://hub.docker.com/r/ffdfgdfg/nps

3.conf文件夹移动到/mydata/npc

4.启动
无配置文件:
docker run -d --name npc --net=host ffdfgdfg/npc
-server=<ip:port> -vkey=<web界面中显示的密钥> <以及一些其他参数>

配置文件:
docker run -d --name npc --net=host \
-v /mydata/npc/conf:/conf ffdfgdfg/npc -config=/conf/npc.conf


5.自启动
sudo docker update npc --restart=always

6.重启
docker restart npc

4.开发环境jdk、maven、idea、vscode

1.版本:
	jdk1.8
	maven3.5.4

2.配置maven阿里云镜像、并以jdk1.8编译
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">

  <localRepository>D:\java\apache\repository</localRepository>
    <mirrors>
	<mirror>
	    <id>aliyun</id>
	    <name>aliyun Maven</name>
	    <mirrorOf>*</mirrorOf>
	    <url>http://maven.aliyun.com/nexus/content/groups/public</url>
	   <!-- <url>http://maven.oschina.net/content/groups/public</url> -->
        </mirror>
    </mirrors>
	
  <profiles>
    <profile>
      <id>jdk-1.8</id>
      <activation>
		<activeByDefault>true</activeByDefault>
        <jdk>1.8</jdk>
      </activation>
	  <properties>
	    <maven.compiler.source>1.8</maven.compiler.source>
	    <maven.compiler.target>1.8</maven.compiler.target>
	    <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
      </properties>
    </profile>
  </profiles>
</settings>

3.idea配置
	配置maven + jdk
	plugins下载lombok、mybatisx、AI
设置自动导入依赖
	setting -> Editor -> general -> Auto Import -> Add + Optimize

4.vscode配置
下载: https://code.visualstudio.com/ 
安装插件:
Auto Close Tag
Auto Rename Tag
Chinese
ESLint
HTML CSS Support
HTML Snippets
JavaScript(ES6)
Live Server
open in browser
Vetur

在这里插入图片描述

5.git配置

步骤:
1.作者信息
用户名:git config --global user.name "WANZENGHUI"
邮箱:git config --global user.email "lemon_wan@aliyun.com"

2.配置ssh登录,不需要账号密码【使用gitee的账户名】
ssh-keygen -t rsa -C "lemon_wan@aliyun.com"【三次回车】
查看秘钥:(复制该秘钥)
cat ~/.ssh/id_rsa.pub【C:\Users\Administrator\.ssh\id_rsa.pub】

3.登录gitee/github -> 设置 -> ssh公钥 -> 将上一步复制内容粘贴在此处

4.测试
ssh -T git@github.com

6.安装nginx

1、调整虚拟机内存3G(free -m查看)
2、创建nginx文件夹
	cd /mydata
	mkdir nginx
3、随便启动一个nginx实例,只是为了复制出配置
	docker run -p 80:80 --name nginx -d nginx:1.10
4、将nginx容器内的配置文件拷贝到当前目录(当前目录在/mydata,此处运行一下命令):
【别忘了后面的点】
	docker container cp nginx:/etc/nginx .
5、终止原容器:docker stop nginx
6、删除原容器:docker rm nginx
7、修改当前nginx文件名字为conf:mv nginx conf
8、创建nginx文件夹:mkdir nginx
9、移动conf到nginx文件夹中:mv conf nginx/
10、创建新的nginx容器:
docker run -p 80:80 --name nginx \
-v /mydata/nginx/html:/usr/share/nginx/html \
-v /mydata/nginx/logs:/var/log/nginx \
-v /mydata/nginx/conf:/etc/nginx \
--privileged=true \
-d nginx:1.10

11、测试:
在html文件夹下创建index.html=》<h1>test</h1>
然后访问:192.168.56.10

12.自启动
sudo docker update nginx --restart=always
13.mkdir es 
在es里面创建fenci.txt文件并且把词汇维护到里面去

项目搭建

坑:
1.idea2018用不了maven3.6,换成3.4
https://blog.csdn.net/weixin_39723544/article/details/101066414 


主模块步骤:
1.创建git项目,登录gitee,如下图创建项目


2.打开idea,使用git拉取项目
New -> Project from version Control -> https://gitee.com/lemon_wan/gulimall.git

3.主项目pom文件:【可以先创建子模块,然后复制子模块的pom文件;模块名gulimall】
创建完主项目pom文件后,点击 加号(add maven project导入主模块pom文件)
<?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>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall</name>
    <description>聚合服务</description>
    <packaging>pom</packaging>

    <modules>
        <module>gulimall-coupon</module>
        <module>gulimall-member</module>
        <module>gulimall-order</module>
        <module>gulimall-product</module>
        <module>gulimall-ware</module>
    </modules>
</project>

4.在配置忽视.gitignore之前,将所以得git弹出框都点取消
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar

**/mvnw
**/mvnw.cmd
**/.mvn
**/target/
.idea
**/.gitignore
HELP.md

5.设置好.gitignore

在这里插入图片描述

设置好.gitignore后,将unversioned File加入版本控制 add to VCS

在这里插入图片描述

1.创建子项目

1.创建5个Spring Initializr子module,
Group:com.atguigu.gulimall
artifact:gulimall-coupon
		  gulimall-member
		  gulimall-order
		  gulimall-product
		  gulimall-ware
type:maven
description:
			谷粒商城-优惠券服务【表:gulimall_sms】
			谷粒商城-会员服务【表:gulimall_ums】
			谷粒商城-订单服务【表:gulimall_oms】
			谷粒商城-商品服务【表:gulimall_pms】
			谷粒商城-仓储服务【表:gulimall_wms】
			
package:com.atguigu.gulimall.coupon
		 com.atguigu.gulimall.member
		 com.atguigu.gulimall.order
		 com.atguigu.gulimall.product
		 com.atguigu.gulimall.ware

//选择一个主配置文件pom当作是项目的配置文件
<?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>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall</name>
    <description>聚合服务</description>
    <packaging>pom</packaging>
    <modules>
        <module>gulimall-coupon</module>
        <module>gulimall-member</module>
        <module>gulimall-order</module>
        <module>gulimall-product</module>
        <module>gulimall-ware</module>
    </modules>
</project>

更改.gitgnore
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
----
**/mvnw
**/mvnw.cmd
**/.mvn
**/target
.idea
**/.gitignore



选中需要导入的依赖:
Web:Spring Web
Spring Cloud Routing:OpenFeign
【注:project configuration files can be added:先不点,配置好.gitignore】

2.修改springboot+springcloud的版本,否则可能会报错
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR6</spring-cloud.version>
    </properties>

在这里插入图片描述

2.数据库初始化(powerdisigner)

简介:
	使用powerdisigner根据数据库设计创建出建表语句
步骤:
	database->generate Database->preview:可以预览所有表创建的sql语句,复制运行即可

3.后台管理系统-renren前后端

简介:
	使用人人开源作为后台管理系统,git上搜索人人开源 然后克隆项目到本地
git clone https://gitee.com/renrenio/renren-fast-vue.git
git clone https://gitee.com/renrenio/renren-fast.git

3.1.renren-fast(后端)

1.clone到gulimall项目中,并删除.git文件,放在项目的文件夹下面
2.gulimall的pom文件配置该renren-fast模块
	<module>renren-fast</module>
3.创建数据库gulimall-admin(基于db.mysql.sql文件)
4.修改配置文件
application-dev.yml
	driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.56.10:3306/gulimall_admin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: root
    然后就可以访问:http://localhost:8080/renren-fast/

3.2.renren-fast-vue(前端)

1.下载安装node.js
	https://nodejs.org/en/【新版需要python环境】 
	https://nodejs.org/dist/【所有版本的镜像,可下载老师一致版本10.16.3】
	检查:cmd-> node -v


2.管理员身份打开vs-code,并打开文件夹renren-fast-vue
【配置npm(类似maven,for JavaScript)】
	在vs-code的控制台依次输入以下命令
	2.1.安装python环境
		方法一:
		手动安装https://www.onlinedown.net/soft/1165640.htm
		配置环境变量:D:\Program Files\python2.7
		
		方法二:
		npm install --global --production windows-build-tools
		配置环境变量:D:\Program Files\python2.7
		
		检查:输入命令python
	
	2.2.以下命令不确定是否全部需要执行
	npm config set registry http://registry.npm.taobao.org/
	npm install cnpm -g --registry=https://registry.npm.taobao.org
	cnpm install -g node-gyp
	npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
	
3.初始化项目
 	cnpm install
 	
4.运行项目
	cnpm run dev
	
异常:
	如果cnpm install用不了,用管理员打开power shell,执行【下面前3条是针对cnpm不能使用的情况】
	1、set-ExecutionPolicy RemoteSigne + 回车
	2、A + 回车
	3、删除node_modules文件夹
	4、cnpm install
	
	
	
一些其他命令:
	cnpm install --save-dev gulp-sass
	cnpm install node-sass --save
	npm rebuild node-sass
	npm uninstall node-sass
解决bug:
 	https://blog.csdn.net/qq_42886417/article/details/103123659
	https://www.cnblogs.com/Wilson6/p/12055389.html
   	http://quanzhan.applemei.com/webStack/TVRnMk13PT0=
最后是看这个解决的:https://www.jianshu.com/p/2823b2f04b82

4.创建公共模块gulimall-common

1.创建
new module->maven->artifactid:gulimall-common->module name:gulimall-common

2.各子模块引入common
        <dependency>
            <groupId>com.atguigu.gulimall</groupId>
            <artifactId>gulimall-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

3.在common中加入公共依赖
        <!--mybatisplus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.2</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
        <!--Query用到StringUtils-->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <!--R中用到的-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.13</version>
        </dependency>

        <!--servlet-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>

4.拷贝renren-fast中下图所示类到common模块中
com.atguigu.common
	exception
	utils
	xss

晚上回来改版本 springboot版本

在这里插入图片描述

5.逆向生成工具

步骤:
1.克隆代码到gulimall项目文件夹中
git clone https://gitee.com/renrenio/renren-generator.git

2.配置pom
<module>renren-generator</module>

3.application.yml
# mysql
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    #MySQL配置
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.56.10:3306/gulimall_pms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: root
	
4.修改generator.properties【重复5遍】
#代码生成器,配置信息

mainPath=com.atguigu
#包名
package=com.atguigu.gulimall
moduleName=product
#作者
author=wanzenghui
#Email
email=lemon_wan@aliyun.com
#表前缀(类名不会包含表前缀)【java bean会去掉表前缀创建bean类】
tablePrefix=pms_

5.修改generator生成模板
	注释掉renren-generator -> resources -> template以下语句:【不使用shiro】
	// import org.apache.shiro.authz.annotation.RequiresPermissions;
	// @RequiresPermissions("${moduleName}:${pathName}:list")

6.运行,访问localhost,选中所有表,点击生成代码
	每一个模块都这样修改运行一次
	
7.下载解压,将main文件整个拷贝到各模块中【重复5遍】

8.非必须:删掉各模块中controller中的shiro注解【如果在generator项目的模板中没有删除的话就需要做这一步骤】
ctrl + shift + R批量修改【使用SpringSecurity】
import org.apache.shiro.authz.annotation.RequiresPermissions;
    @RequiresPermissions("product:attrattrgrouprelation:list")
    @RequiresPermissions("product:attrattrgrouprelation:info")
    @RequiresPermissions("product:attrattrgrouprelation:save")
    @RequiresPermissions("product:attrattrgrouprelation:update")
    @RequiresPermissions("product:attrattrgrouprelation:delete")
    @RequiresPermissions("product:attr:list")
    @RequiresPermissions("product:attr:info")
    @RequiresPermissions("product:attr:save")
    @RequiresPermissions("product:attr:update")
    @RequiresPermissions("product:attr:delete") 
	...
	
9.删除生成的vue代码

6.整合mybatisplus

版本映射:

在这里插入图片描述

步骤:
1、整合mybatis-plus
	1)common模块导入依赖
		<!--mybatisplus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.2</version>
        </dependency>
    
    2)代码层面整合,参照文档:https://mp.baomidou.com/guide/config.html
		1、配置数据源
			1)导入数据库驱动依赖【要跟数据库版本一致,我的是5.7.31】
  				官方文档,版本对应:https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-versions.html
                在common模块导入依赖:
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>8.0.17</version>
                </dependency>
			2)在product中创建application.yml
                spring:
                  datasource:
                    username: root
                    password: root
                    url: jdbc:mysql://192.168.56.10:3306/gulimall_pms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
                    driver-class-name: com.mysql.cj.jdbc.Driver

		2、配置mybatis-plus
			1)在product模块的Application类上@MapperScan("com.atguigu.gulimall.product.dao")
			【如果Dao类上配置了@Repository可以不配】
                        
			2)告诉mybatis-plus,sql映射文件xml的位置,
				在yml中配置,classpath*表示不止扫描自己的类路径,还扫描依赖的jar包的类路径
				mybatis-plus:
  					mapper-locations: classpath:/mapper/**/*.xml
  					
			3)设置主键的类型是自增的,默认是NONE,不是自增
				mybatis-plus:
                  mapper-locations: classpath:/mapper/**/*.xml
                  global-config:
                    db-config:
                      id-type: auto

6.1.逻辑删除

方案一:全局配置
1)配置相关逻辑删除规则
2)配置相关组件(3.1.2后可省略)
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
     -- logic-delete-field: showStatus  # 全局逻辑删除的实体字段名【注:这个不要配置,否则整个服务都配置上了】
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
      
方案二:
/**
* 该值会覆盖全局配置
*/
@TableLogic(value = "1", delval = "0")//value:默认逻辑未删除值;delval:默认逻辑删除值
private Integer showStatus;

7.配置各子模块(端口占用)

1.各子模块端口配置【coupon:7000、member:8000、order:9000、product:10000、ware:11000】
server:
	port: 7000

2.启动所有服务(如果出现端口占用以下命令解决)
netstat -ano 查出端口对应的进程ID=》PID,打开控制台关闭
netstat -ano|findstr "13048" 找到对应的进程,在任务管理器里面关闭进程

3.测试接口
localhost:7000/coupon/coupon/list

4.测试持久层
@RunWith(SpringRunner.class)
@SpringBootTest
class GulimallProductApplicationTests {

    @Autowired
    BrandService brandService;
    
    @Test
    void contextLoads() {
        BrandEntity entity = new BrandEntity();
        entity.setName("华为");
        boolean save = brandService.save(entity);
        System.out.println("保存成功:" + save);
    }
    // 查询条件Wrapper,brand_id = 1的,链式编程拼接多个条件
    @Test
    void queryPage() {
        //brandService.queryPage()
        List<BrandEntity> list = brandService.list(new QueryWrapper<BrandEntity>().eq("brand_id", 1L));
        list.forEach((item)->{
            System.out.println(item);
        });
    }
}

8.日志级别

日志级别使用debug,控制台打印sql语句

logging:
  level:
    com.atguigu.gulimall: debug

分布式环境搭建

搭配方案

注册中心(服务发现/注册):SpringCloud Alibaba - Nacos【代替Eureka、config】
配置中心(动态配置管理):SpringCloud Alibaba - Nacos
负载均衡:SpringCloud - Ribbon【】
声明式HTTP客户端(调用远程服务):SpringCloud - OpenFeign【代替Feign】
服务容错(限流、降级、熔断):SpringCloud Alibaba - Sentinel【代替Hystrix】
网关:SpringCloud - GateWay【webflux编程模式,代替zuul】
调用链监控:SpringCloud - Sleuth
分布式事务解决方案:SpringCloud Alibaba - Seata【原Fescar】

SpringCloud Alibaba文档:
https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies?__cf_chl_tk=ZJXGWmW6mSDwmmgZlkMrWCYcBbmljuMwHRjIAThLN3E-1670480605-0-gaNycGzNDD0

1.spring-cloud-alibaba依赖

在common模块配置依赖:
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>


对于springboot2.7.6而言
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

2.Nacos服务注册发现

nacos——demo:
https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md
1.在common模块配置依赖:
<!--服务注册发现-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

//亲自做了的效果需要加版本号才可以
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>
        
2.下载服务端
https://github.com/alibaba/nacos/releases/tag/1.3.1
下载完成运行 startup.cmd

3.在各子模块添加nacos服务端ip+port,并配置各模块服务名【不配置名字nacos服务端服务列表不会显示】
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: gulimall-coupon
    
4.各模块启动类配置注解,作为客户端
@EnableDiscoveryClient

5.查看注册情况【账号/密码:nacos/nacos】
http://127.0.0.1:8848/nacos

3.OpenFeign声明式远程调用

简介:
	Feign是一个声明式的HTTP客户端,目的就是让远程调用更加简单
	Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息
	Feign整合了Ribbon (负载均衡)和Hystrix(服务熔断),可以让我们不再需要显式地使用这两个组件。
流程:
	1.启动类加上两个注解【1.添加当前项目到注册中心;2.开启远程调用】
	2.@FeignClient定义被调用服务名
	3.feign从注册中心拉取服务
	4.负载均衡找到真正的ip+port
	5.搭配方法上@RequestMapping指定的请求路径访问指定controller

步骤:
1.导入依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2.增加接口测试类
package com.atguigu.gulimall.member.feign;
import org.springframework.cloud.openfeign.FeignClient;
@FeignClient("gulimall-coupon")
public interface CouponFeignService {
}

    
3.开启远程调用,调用方Application主类上添加注解(spring启动后会扫描此包下的所有@FeignClient修饰的接口)
@EnableFeignClients(basePackages="com.atguigu.gulimall.member.feign")
    
4.coupon模块增加测试接口
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;

    @RequestMapping("/member/list")
    public R membercoupons() {
        CouponEntity entity = new CouponEntity();
        entity.setCouponName("满100减10");
        return R.ok().put("coupons", Arrays.asList(entity));
    }
}

5.CouponFeignService增加远程调用方法
@FeignClient("gulimall-coupon")
public interface CouponFeignService {
    
    /**
     * 测试openFeign
     */
    @RequestMapping("/coupon/coupon/member/list")
    public R membercoupons();
    
}

6.member增加测试请求
@RestController
@RequestMapping("member/member")
public class MemberController {
    @Autowired
    private MemberService memberService;

    @Autowired
    private CouponFeignService couponFeignService;

    /**
     * openFeign测试接口
     */
    @RequestMapping("/coupons")
    public R test() {
        MemberEntity entity = new MemberEntity();
        entity.setNickname("张三");

        R membercoupons = couponFeignService.membercoupons();
        Object coupons = membercoupons.get("coupons");
        return R.ok().put("member", entity).put("coupons", coupons);
    }
}

!!!!!!!!!!!!!!!!!!!!!!!!!!!出错点应该!!!!!!!!!!!!!!!!!!!!!!!!
    
SpringCloud FeignHoxton.M2 RELEASED版本之后不再使用ribbon而是使用spring-cloud-loadbalancer,所以在不引入spring-cloud-loadbalancer情况下会报错
 <!-- 负载均衡-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
            <version>3.0.3</version>
        </dependency>
    
!!!!!!!!!!错误:org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.choose!!!!!!!!!
原文链接:https://blog.csdn.net/qq_52476654/article/details/125692501
主要原因是还是jar包冲突,nacos依赖的ribbon和springcloud的ribbon存在同个方法的不同实现,不兼容。
排除掉nacos的spring-cloud-starter-netflix-ribbon依赖:
1.<!-- nacos discovery starter -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-netflex-ribbon</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-netflex-ribbon</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
   
2.排除调nacos里面的ribbon
Maven: org.springframework.cloud:spring-cloud-netflix-ribbon:2.2.10.RELEASE
Maven: org.springframework.cloud; spring-cloud-starter-netflix-ribbon:2.2.10.RELEASE
    
原文链接:https://blog.csdn.net/weixin_44592837/article/details/125005325
7.访问测试请求
http://localhost:8000/member/member/coupons

4.Nacos Config配置管理

简介:
	demo:https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md
	不使用配置管理的劣势:集群环境下需要修改配置后打包多份发布
	优势:不用重新打包+发布,可以动态刷新配置,由nacos服务端来发布
	
	使用方式
	1.引入依赖
	<!--服务的配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>
	
	2.创建一个bootstrap.properties 
	添加配置项地址
	spring.application.name=gulimall-coupon
	spring.cloud.nacos.config.server-addr=127.0.0.1:8848
	
	3.点击配置导入,给配置中心添加一个(Data Id)gulimall-coupon.properties。默认规则:应用名.properties
	4.给应用名.properties 添加任何配置
	5.动态获取配置  
	@RefreshScope  加在控制层里面
	@Value 获取到配置文件里面的值
	规则:如果当前配置application.properties里面配置了东西优先加载nacos配置中心里面的配置

	在日志的这个地方将服务名写进配置:Ignore the empty nacos configuration and get it based on dataId[gulimall-coupon.properties] & group[DEFAULT_GROUP]
	
	注意:
<!--springboot 2.4以上需要加上这个依赖bootstrap才可以生效-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>3.1.0</version>
        </dependency>
	
	
	
	
	1)命名空间:配置隔离;【默认使用public(保留空间)】默认新增的所有配置都在public空间里面
		1.比如说:开发,测试,生产:利用命名空间做,基于环境隔离
		2.也可以对于每一个微服务进行命名,创建每一个微服务的命名空间,只加载自己命名空间的所有配置,基于微服务隔离
	使用:以模块来区分命名空间【各模块使用自己的命名空间】
	注意:在bootstrap.properties;配置使用的命名空间,配置命名空间的唯一id
	spring.cloud.nacos.config.namespace=81b480b2-f3b7-4251-849d-e18056e79e0e
	
	2)配置分组:
	默认:所有配置属于DEFAULT_GROUP组
	在bootstrap.properties里面添加
	spring.cloud.nacos.config.group=维护的配置组名(DEFAULT_GROUP)
	
	3)配置ID:类似文件名【默认 服务名.properties】
	默认:gulimall-product.properties

	4)配置集:指的是一组配置文件共同生效,拆分gulimall-product.properties内的配置放在不同的配置文件中
	注意:【属性名相同的配置以gulimall-product.properties为主】
	mybatis.yml
	datasource.yml
	other.yml

spring.application.name=gulimall-product
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=95c36bd7-fd1a-4914-a8d8-7a64fa889258

spring.cloud.nacos.config.group=维护的配置组名(DEFAULT_GROUP)加载默认配置文件的时候进行默认的分组

spring.cloud.nacos.config.extension-configs[0].data-id=datasource.yml   具体的哪一个配置
spring.cloud.nacos.config.extension-configs[0].group=dev                具体的哪一个分组
spring.cloud.nacos.config.extension-configs[0].refresh=true				配置中心这个配置改掉过后该微服务是否需要刷新配置

spring.cloud.nacos.config.extension-configs[1].data-id=mybatis.yml   具体的哪一个配置
spring.cloud.nacos.config.extension-configs[1].group=dev                具体的哪一个分组
spring.cloud.nacos.config.extension-configs[1].refresh=true				配置中心这个配置改掉过后该微服务是否需要刷新配置


spring.cloud.nacos.config.extension-configs[2].data-id=other.yml   具体的哪一个配置
spring.cloud.nacos.config.extension-configs[2].group=dev                具体的哪一个分组
spring.cloud.nacos.config.extension-configs[2].refresh=true				配置中心这个配置改掉过后该微服务是否需要刷新配置

控制台会自动展示出那些配置被读取了,gulimall-product.properties这个配置文件是会被自动读取!

【本项目的使用规则】:以每一个微服务来划分 (coupon)命名空间,以dev,test,prod来划分配置分组

同时加载很多个配置
1.微服务的所有配置都可以放在配置中心中。
2.只需要在bootstrap.properties说明加载配置中心中的哪些配置文件即可
@value,@ConfigurationProperties。。。。
以前springboot任何方法从配置文件中获取值都能使用,配置中心优先使用配置中心中的

步骤:
1.在common模块中导入依赖:
 <dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
 </dependency>

访问127.0.0.1:8848/nacos完成以下新增动作

2.新建命名空间:product

3.选中命名空间product,新增配置集并指定分组dev【属性名相同的配置以gulimall-product.properties为主】
Data ID:mybatis.yml
Group:dev

Data ID:datasource.yml
Group:dev

Data ID:spring.yml
Group:dev

4.新增配置文件:/src/main/resources/bootstrap.properties【会比application.properties先被加载】
	1.指定Nacos配置中心的server-addr
	2.指定当前服务服务名【否则不会在注册中心中显示】
	3.指定命名空间【未指定,使用默认public】
	4.指定分组【未指定,使用默认DEFAULT_GROUPS   Data Id=gulimall-coupon的文件】
	5.开启热发布热加载【默认开启】
	6.指定配置集【多个yml】
	
spring.application.name=gulimall-product
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=95c36bd7-fd1a-4914-a8d8-7a64fa889258
spring.cloud.nacos.config.group=dev
#如果这个dev不放开的话,默认的gulimall-coupon不生效【会加载dev分组下的所有配置】

spring.cloud.nacos.config.extension-configs[0].data-id=datasource.yml
spring.cloud.nacos.config.extension-configs[0].group=dev
spring.cloud.nacos.config.extension-configs[0].refresh=true

spring.cloud.nacos.config.extension-configs[1].data-id=mybatis.yml
spring.cloud.nacos.config.extension-configs[1].group=dev
spring.cloud.nacos.config.extension-configs[1].refresh=true

spring.cloud.nacos.config.extension-configs[2].data-id=spring.yml
spring.cloud.nacos.config.extension-configs[2].group=dev
spring.cloud.nacos.config.extension-configs[2].refresh=true

5.在需要热加载的配置类上添加注解
@RefreshScope【加入该注解后,使用@Value获取值会以热加载形式加载】

新建配置:

在这里插入图片描述

5.Gateway网关

简介:
	路由:将访问网关的url转换为正确的ip+port(集群),并且能感知服务的上线和熔断【否则需要在前端来改端口+ip】
	过滤
	监控
	鉴权
	限流
	日志输出,避免各模块重复代码
	springcloud Gateway比zuul(Netflix)更优秀
	
	doc文档,查看GA稳定版
https://docs.spring.io/spring-cloud-gateway/docs/2.2.4.RELEASE/reference/html/
中文文档:https://www.springcloud.cc/spring-cloud-greenwich.html#gateway-starter

	gateway网关三个概念:【断言成功后跳转路由指定url】
		路由:路由之间通过ID区分 + 一个目的地URI + 断言集合组成 + 过滤器
		断言:条件判断,根据请求参数/请求头等进行判断,为true通过【查看官方文档有哪些断言】(经过一些的条件判断你这个请求需要发送或者链接到哪个url或者说是服务)
		过滤器:请求之前/响应之后 可以进行过滤,【查看官方文档有哪些过滤器】

各模块之间关系:
在这里插入图片描述

每秒处理请求次数:

在这里插入图片描述

网关处理过程:

在这里插入图片描述

**demo1:**当前请求是否在某时间之后
在这里插入图片描述

**demo2:**过滤器,在请求头添加参数 key:X-Request-Foo,value:Bar

在这里插入图片描述

步骤:
1.创建Spring Init网关模块,添加网关依赖
com.atguigu.gulimall
gulimall-gateway
com.atguigu.gulimall.gateway

2.将gateway的springboot版本改成一致的版本
  将gateway的springcloud版本改成一致的版本
  gateway模块添加common依赖

3.maven中添加对common的依赖,并且在主pom里添加网关模块
<module>gulimall-gateway</module>

4.在Application加上注解
	@EnableDiscoveryClient
	
5.配置注册中心的地址application.yml
server:
  port: 88

spring:
  application:
    name: gulimall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

6.配置中心的地址bootstrap.properties
spring.application.name=gulimall-gateway
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

7.启动异常:Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
解决:方法1、移除mybatis相关依赖
        <dependency>
            <groupId>com.atguigu.gulimall</groupId>
            <artifactId>gulimall-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <groupId>com.baomidou</groupId>
                    <artifactId>mybatis-plus-boot-starter</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
	 方法2、移除DataSourceAutoConfiguration【加载Application类上】
		@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})

8.实现以下要求:
127.0.0.1:88/hello?url=test1  跳转https://www.cnblogs.com/wu-song/p/7929595.html

server:
  port: 88
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      
      - id: test1_route
        uri: https://www.cnblogs.com/wu-song/p/7929595.html
        predicates:
        - Query=url,test1

前端环境

ES6

简介:
	前端语言的规范,每年都会出一个新标准ECMAScript 2018->ES9

ES6:语法新特性【重点】
Node.js:npm包管理工具,相当于maven
Vue:相当于springmvc【重点】  
Babel:是一个javascript编译器,自动转换为浏览器兼容的代码
webpack:自动化项目构建工具,gulp也是同类产品



步骤:
1、打开vscode,打开文件夹->新建文件夹->es6
2、新建文件let.html,shift+!回车快速生成HTML文档
3、右键 open with live server【浏览器查看】

let&&const
var在{}之外也起作用
let在{}之外不起作用
var多次声明同一变量不会报错,let多次声明会报错,只能声明一次。
var 会变量提升(打印和定义可以顺序反)。let 不存在变量提升(顺序不能反)
const声明之后不允许改变

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    

    <script>
       // var 声明的变量往往会越域
       // let 声明的变量有严格局部作用域
//         {
//             var a = 1;
//             let b = 2;
//         }
//         console.log(a);  // 1
//         console.log(b);  // ReferenceError: b is not defined

    // var 可以声明多次
            // let 只能声明一次
//         var m = 1
//         var m = 2
//         let n = 3
//       let n = 4
//         console.log(m)  // 2
//         console.log(n)  // Identifier 'n' has already been declared

        // var 会变量提升
        // let 不存在变量提升
//         console.log(x);  // undefined
//         var x = 10;
//         console.log(y);   //ReferenceError: y is not defined
//         let y = 20;

        // const
        // 1. const声明之后不允许改变
        // 2. 一但声明必须初始化,否则会报错
        const a = 1;
        a = 3; //Uncaught TypeError: Assignment to constant variable.
    
    </script>

</body>
</html>


解构表达式
支持let arr = [1,2,3]; let [a,b,c] = arr;这种语法
支持对象解析:const { name: abc, age, language } = person; 冒号代表改名
字符串函数
支持一个字符串为多行
占位符功能 ${}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

    <script>
        //数组解构
        // let arr = [1,2,3];
        // // let a = arr[0];
        // // let b = arr[1];
        // // let c = arr[2];

        // let [a,b,c] = arr;
        // console.log(a,b,c)

        const person = {
            name: "jack",
            age: 21,
            language: ['java', 'js', 'css']
        }
        //         const name = person.name;
        //         const age = person.age;
        //         const language = person.language;

        //对象解构
        const { name: abc, age, language } = person;
        console.log(abc, age, language)

        // 字符串扩展
        let str = "hello.vue";
        console.log(str.startsWith("hello"));//true
        console.log(str.endsWith(".vue"));//true
        console.log(str.includes("e"));//true
        console.log(str.includes("hello"));//true

        //字符串模板
        let ss = `<div>
                    <span>hello world<span>
                </div>`;
        console.log(ss);

        // 字符串插入变量和表达式。变量名写在 ${} 中,${} 中可以放入 JavaScript 表达式。

        function fun() {
            return "这是一个函数"
        }

        let info = `我是${abc},今年${age + 10}了, 我想说: ${fun()}`;
        console.log(info);

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


函数优化
原来想要函数默认值得这么写b = b || 1; 现在可以直接写了function add2(a, b = 1) {
函数不定参数function fun(...values) {
支持箭头函数(lambda表达式),还支持使用{}结构传入对象的成员

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

    <script>
        //在ES6以前,我们无法给一个函数参数设置默认值,只能采用变通写法:
        function add(a, b) {
            // 判断b是否为空,为空就给默认值1
            b = b || 1;
            return a + b;
        }
        // 传一个参数
        console.log(add(10));


        //现在可以这么写:直接给参数写上默认值,没传就会自动使用默认值
        function add2(a, b = 1) {
            return a + b;
        }
        console.log(add2(20));


        //不定参数
        function fun(...values) {
            console.log(values.length)
        }
        fun(1, 2)      //2
        fun(1, 2, 3, 4)  //4

        //箭头函数
        //以前声明一个方法
        // var print = function (obj) {
        //     console.log(obj);
        // }
        var print = obj => console.log(obj);
        print("hello");

        var sum = function (a, b) {
            c = a + b;
            return a + c;
        }

        var sum2 = (a, b) => a + b;
        console.log(sum2(11, 12));

        var sum3 = (a, b) => {
            c = a + b;
            return a + c;
        }
        console.log(sum3(10, 20))


        const person = {
            name: "jack",
            age: 21,
            language: ['java', 'js', 'css']
        }

        function hello(person) {
            console.log("hello," + person.name)
        }

        //箭头函数+解构
        var hello2 = ({name}) => console.log("hello," +name);
        hello2(person);

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


对象优化
可以获取map的键值对等Object.keys()、values、entries
Object.assgn(target,source1,source2) 合并
const person2 = { age, name } //声明对象简写
…代表取出该对象所有属性拷贝到当前对象。let someone = { …p1 }


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script>
        const person = {
            name: "jack",
            age: 21,
            language: ['java', 'js', 'css']
        }

        console.log(Object.keys(person));//["name", "age", "language"]
        console.log(Object.values(person));//["jack", 21, Array(3)]
        console.log(Object.entries(person));//[Array(2), Array(2), Array(2)]

        const target = { a: 1 };
        const source1 = { b: 2 };
        const source2 = { c: 3 };

        //{a:1,b:2,c:3}
        Object.assign(target, source1, source2);

        console.log(target);//["name", "age", "language"]

        // 声明对象简写
        const age = 23
        const name = "张三"
        const person1 = { age: age, name: name }

        const person2 = { age, name }//声明对象简写
        console.log(person2);

        // 对象的函数属性简写
        let person3 = {
            name: "jack",
            // 以前:
            eat: function (food) {
                console.log(this.name + "在吃" + food);
            },
            //箭头函数this不能使用,对象.属性
            eat2: food => console.log(person3.name + "在吃" + food),
            eat3(food) {
                console.log(this.name + "在吃" + food);
            }
        }

        person3.eat("香蕉");
        person3.eat2("苹果")
        person3.eat3("橘子");

        // 对象拓展运算符

        //  拷贝对象(深拷贝)
        let p1 = { name: "Amy", age: 15 }
        let someone = { ...p1 }
        console.log(someone)  //{name: "Amy", age: 15}

        //  合并对象
        let age1 = { age: 15 }
        let name1 = { name: "Amy" }
        let p2 = {name:"zhangsan"}
        p2 = { ...age1, ...name1 } 
        console.log(p2)
    </script>
</body>

</html>


map和reduce
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    
    <script>
        //数组中新增了map和reduce方法。
        //map():接收一个函数,将原数组中的所有元素用这个函数处理后放入新数组返回。
         let arr = ['1', '20', '-5', '3'];
         
        //  arr = arr.map((item)=>{
        //     return item*2
        //  });
         arr = arr.map(item=> item*2);

        

         console.log(arr);
        //reduce() 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,
        //[2, 40, -10, 6]
        //arr.reduce(callback,[initialValue])
        /**
     1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
    2、currentValue (数组中当前被处理的元素)
    3、index (当前元素在数组中的索引)
    4、array (调用 reduce 的数组)*/
        let result = arr.reduce((a,b)=>{
            console.log("上一次处理后:"+a);
            console.log("当前正在处理:"+b);
            return a + b;
        },100);
        console.log(result)

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


promise
以前嵌套ajax的时候很繁琐。

解决方案:
把Ajax封装到Promise中,赋值给let p
在Ajax中成功使用resolve(data),交给then处理,
失败使用reject(err),交给catch处理p.then().catch()


corse_score_10.json 得分
{
    "id": 100,
    "score": 90
}

user.json 用户
{
    "id": 1,
    "name": "zhangsan",
    "password": "123456"
}


user_corse_1.json 课程
{
    "id": 10,
    "name": "chinese"
}


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
    <script>
        //1、查出当前用户信息
        //2、按照当前用户的id查出他的课程
        //3、按照当前课程id查出分数
        // $.ajax({
        //     url: "mock/user.json",
        //     success(data) {
        //         console.log("查询用户:", data);
        //         $.ajax({
        //             url: `mock/user_corse_${data.id}.json`,
        //             success(data) {
        //                 console.log("查询到课程:", data);
        //                 $.ajax({
        //                     url: `mock/corse_score_${data.id}.json`,
        //                     success(data) {
        //                         console.log("查询到分数:", data);
        //                     },
        //                     error(error) {
        //                         console.log("出现异常了:" + error);
        //                     }
        //                 });
        //             },
        //             error(error) {
        //                 console.log("出现异常了:" + error);
        //             }
        //         });
        //     },
        //     error(error) {
        //         console.log("出现异常了:" + error);
        //     }
        // });


        //1、Promise可以封装异步操作
        // let p = new Promise((resolve, reject) => { //传入成功解析,失败拒绝
        //     //1、异步操作
        //     $.ajax({
        //         url: "mock/user.json",
        //         success: function (data) {
        //             console.log("查询用户成功:", data)
        //             resolve(data);
        //         },
        //         error: function (err) {
        //             reject(err);
        //         }
        //     });
        // });

        // p.then((obj) => { //成功以后做什么
        //     return new Promise((resolve, reject) => {
        //         $.ajax({
        //             url: `mock/user_corse_${obj.id}.json`,
        //             success: function (data) {
        //                 console.log("查询用户课程成功:", data)
        //                 resolve(data);
        //             },
        //             error: function (err) {
        //                 reject(err)
        //             }
        //         });
        //     })
        // }).then((data) => { //成功以后干什么
        //     console.log("上一步的结果", data)
        //     $.ajax({
        //         url: `mock/corse_score_${data.id}.json`,
        //         success: function (data) {
        //             console.log("查询课程得分成功:", data)
        //         },
        //         error: function (err) {
        //         }
        //     });
        // })

        function get(url, data) { //自己定义一个方法整合一下
            return new Promise((resolve, reject) => {
                $.ajax({
                    url: url,
                    data: data,
                    success: function (data) {
                        resolve(data);
                    },
                    error: function (err) {
                        reject(err)
                    }
                })
            });
        }

        get("mock/user.json")
            .then((data) => {
                console.log("用户查询成功~~~:", data)
                return get(`mock/user_corse_${data.id}.json`);
            })
            .then((data) => {
                console.log("课程查询成功~~~:", data)
                return get(`mock/corse_score_${data.id}.json`);
            })
            .then((data)=>{
                console.log("课程成绩查询成功~~~:", data)
            })
            .catch((err)=>{ //失败的话catch
                console.log("出现异常",err)
            });

    </script>
</body>

</html>


模块化
模块化就是把代码进行拆分,方便重复利用。类似于java中的导包,
而JS换了个概念,是导模块。

模块功能主要有两个命令构成 export 和import

export用于规定模块的对外接口
import用于导入其他模块提供的功能


user.js
var name = "jack"
var age = 21
function add(a,b){
    return a + b;
}

export {name,age,add}

hello.js
// export const util = {
//     sum(a, b) {
//         return a + b;
//     }
// }

export default {
    sum(a, b) {
        return a + b;
    }
}
// export {util}

//`export`不仅可以导出对象,一切JS变量都可以导出。比如:基本类型变量、函数、数组、对象。


main.js
import abc from "./hello.js"
import {name,add} from "./user.js"

abc.sum(1,2);
console.log(name);
add(1,3);

Vue

MVVM思想
MVVM思想

M:model 包括数据和一些基本操作
V:view 视图,页面渲染结果
VM:View-model,模型与视图间的双向操作(无需开发人员干涉)
视图和数据通过VM绑定起来,model里有变化会自动地通过Directives填写到视view中,
视图表单中添加了内容也会自动地通过DOM Listeners保存到模型中。

基础案例
在VSCode中安装vue 2 snippets语法提示插件,在谷歌浏览器中安装vue.js devtools
npm init -y
npm install vue
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>

    <div id="app">
        <input type="text" v-model="num">
        v-model实现双向绑定
        <button v-on:click="num++">点赞</button>
        v-on:click绑定事件,实现自增
        <button v-on:click="cancel">取消</button>
        回到自定义的方法
        
        <h1> {{name}} ,非常帅,有{{num}}个人为他点赞{{hello()}}</h1>
    </div>

    <!-- 导入依赖 -->
    <script src="./node_modules/vue/dist/vue.js"></script>

    <script>
        //1、vue声明式渲染
        let vm = new Vue({ //生成vue对象
            el: "#app",//绑定元素 div id="app"
            data: {  //封装数据
                name: "张三",  // 也可以使用{} //表单中可以取出
                num: 1
            },
            methods:{  //封装方法
                cancel(){
                    this.num -- ;
                },
                hello(){
                    return "1"
                }
            }
        });
        还可以在html控制台vm.name

        //2、双向绑定,模型变化,视图变化。反之亦然。
        //3、事件处理

        //v-xx:指令

        //1、创建vue实例,关联页面的模板,将自己的数据(data)渲染到关联的模板,响应式的
        //2、指令来简化对dom的一些操作。
        //3、声明方法来做更复杂的操作。methods里面可以封装方法。

    </script>
</body>

</html>

v-text、v-html.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
   
    <div id="app">
        {{msg}}  {{1+1}}  {{hello()}}<br/>
        用v-html取内容
        <span v-html="msg"></span>
        
        <br/>
        原样显示
        <span v-text="msg"></span>

        
    </div>
   
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        new Vue({
            el:"#app",
            data:{
                msg:"<h1>Hello</h1>",
                link:"http://www.baidu.com"
            },
            methods:{
                hello(){
                    return "World"
                }
            }
        })
    </script>
    
</body>
</html>

插值表达式
花括号:只能写在标签体内,不能用在标签内。用v-bind解决
{{}}必须有返回值

单向绑定v-bind
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

    <!-- 给html标签的属性绑定 -->
    <div id="app"> 

        <a v-bind:href="link">gogogo</a>

        <!-- class,style  {class名:加上?}-->
        <span v-bind:class="{active:isActive,'text-danger':hasError}"
          :style="{color: color1,fontSize: size}">你好</span>


    </div>

    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        let vm = new Vue({
            el:"#app",
            data:{
                link: "http://www.baidu.com",
                isActive:true,
                hasError:true,
                color1:'red',
                size:'36px'
            }
        })
    </script>

</body>
</html>

双向绑定v-model
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

    <!-- 表单项,自定义组件 -->
    <div id="app">

        精通的语言:
            <input type="checkbox" v-model="language" value="Java"> java<br/>
            <input type="checkbox" v-model="language" value="PHP"> PHP<br/>
            <input type="checkbox" v-model="language" value="Python"> Python<br/>
        选中了 {{language.join(",")}}
    </div>
    
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        let vm = new Vue({
            el:"#app",
            data:{
                language: []
            }
        })
    </script>

</body>
</html>

v-on
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
                
        <!--事件中直接写js片段-->
        <button v-on:click="num++">点赞</button>
        <!--事件指定一个回调函数,必须是Vue实例中定义的函数-->
        <button @click="cancel">取消</button>
        <!--  -->
        <h1>有{{num}}个赞</h1>


        <!-- 事件修饰符 -->
        <div style="border: 1px solid red;padding: 20px;" v-on:click.once="hello">
            大div
            <div style="border: 1px solid blue;padding: 20px;" @click.stop="hello">
                小div <br />
                <a href="http://www.baidu.com" @click.prevent.stop="hello">去百度</a>
            </div>
        </div>



        <!-- 按键修饰符: -->
        <input type="text" v-model="num" v-on:keyup.up="num+=2" @keyup.down="num-=2" @click.ctrl="num=10"><br />

        提示:

    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        new Vue({
            el:"#app",
            data:{
                num: 1
            },
            methods:{
                cancel(){
                    this.num--;
                },
                hello(){
                    alert("点击了")
                }
            }
        })
    </script>
</body>

</html>

v-for
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>

    <div id="app">
        <ul>
            <li v-for="(user,index) in users" :key="user.name" v-if="user.gender == '女'">
                <!-- 1、显示user信息:v-for="item in items" -->
               当前索引:{{index}} ==> {{user.name}}  ==>   {{user.gender}} ==>{{user.age}} <br>
                <!-- 2、获取数组下标:v-for="(item,index) in items" -->
                <!-- 3、遍历对象:
                        v-for="value in object"
                        v-for="(value,key) in object"
                        v-for="(value,key,index) in object" 
                -->
                对象信息:
                <span v-for="(v,k,i) in user">{{k}}=={{v}}=={{i}};</span>
                <!-- 4、遍历的时候都加上:key来区分不同数据,提高vue渲染效率 -->
            </li>

            
        </ul>

        <ul>
            <li v-for="(num,index) in nums" :key="index"></li>
        </ul>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>         
        let app = new Vue({
            el: "#app",
            data: {
                users: [{ name: '柳岩', gender: '女', age: 21 },
                { name: '张三', gender: '男', age: 18 },
                { name: '范冰冰', gender: '女', age: 24 },
                { name: '刘亦菲', gender: '女', age: 18 },
                { name: '古力娜扎', gender: '女', age: 25 }],
                nums: [1,2,3,4,4]
            },
        })
    </script>
</body>

</html>

v-if和v-show
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <!-- 
        v-if,顾名思义,条件判断。当得到结果为true时,所在的元素才会被渲染。
        v-show,当得到结果为true时,所在的元素才会被显示。 
    -->
    <div id="app">
        <button v-on:click="show = !show">点我呀</button>
        <!-- 1、使用v-if显示 -->
        <h1 v-if="show">if=看到我....</h1>
        <!-- 2、使用v-show显示 -->
        <h1 v-show="show">show=看到我</h1>
    </div>

    <script src="../node_modules/vue/dist/vue.js"></script>
        
    <script>
        let app = new Vue({
            el: "#app",
            data: {
                show: true
            }
        })
    </script>

</body>

</html>

v-else和v-else-if
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <button v-on:click="random=Math.random()">点我呀</button>
        <span>{{random}}</span>

        <h1 v-if="random>=0.75">
            看到我啦?! &gt;= 0.75
        </h1>

        <h1 v-else-if="random>=0.5">
            看到我啦?! &gt;= 0.5
        </h1>

        <h1 v-else-if="random>=0.2">
            看到我啦?! &gt;= 0.2
        </h1>

        <h1 v-else>
            看到我啦?! &lt; 0.2
        </h1>

    </div>


    <script src="../node_modules/vue/dist/vue.js"></script>
        
    <script>         
        let app = new Vue({
            el: "#app",
            data: { random: 1 }
        })     
    </script>
</body>

</html>

计算属性和侦听器
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <!-- 某些结果是基于之前数据实时计算出来的,我们可以利用计算属性。来完成 -->
        <ul>
            <li>西游记; 价格:{{xyjPrice}},数量:<input type="number" v-model="xyjNum"> </li>
            <li>水浒传; 价格:{{shzPrice}},数量:<input type="number" v-model="shzNum"> </li> 
            <li>总价:{{totalPrice}}</li>
            {{msg}}
        </ul>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>
        //watch可以让我们监控一个值的变化。从而做出相应的反应。
        new Vue({
            el: "#app",
            data: {
                xyjPrice: 99.98,
                shzPrice: 98.00,
                xyjNum: 1,
                shzNum: 1,
                msg: ""
            },
            computed: {
                totalPrice(){
                    return this.xyjPrice*this.xyjNum + this.shzPrice*this.shzNum
                }
            },
            watch: {
                xyjNum(newVal,oldVal){
                    if(newVal>=3){
                        this.msg = "库存超出限制";
                        this.xyjNum = 3
                    }else{
                        this.msg = "";
                    }
                }
            },
        })
    </script>

</body>

</html>

过滤器
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <!-- 过滤器常用来处理文本格式化的操作。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 -->
    <div id="app">
        <ul>
            <li v-for="user in userList">
                {{user.id}} ==> {{user.name}} ==> {{user.gender == 1?"男":"女"}} ==>
                {{user.gender | genderFilter}} ==> {{user.gender | gFilter}}
            </li>
        </ul>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>

    <script>

        Vue.filter("gFilter", function (val) {
            if (val == 1) {
                return "男~~~";
            } else {
                return "女~~~";
            }
        })

        let vm = new Vue({
            el: "#app",
            data: {
                userList: [
                    { id: 1, name: 'jacky', gender: 1 },
                    { id: 2, name: 'peter', gender: 0 }
                ]
            },
            filters: {
                 filters 定义局部过滤器,只可以在当前vue实例中使用
                genderFilter(val) {
                    if (val == 1) {
                        return "男";
                    } else {
                        return "女";
                    }
                }
            }
        })
    </script>
</body>

</html>

组件化
在大型应用开发的时候,页面可以划分成很多部分。往往不同的页面,也会有相
同的部分。
例如可能会有相同的头部导航。
但是如果每个页面都自开发,这无疑增加了我们开发的成本。所以我们会把页面
的不同分拆分成立的组件,然后在不同页面就可以共享这些组件,避免重复开发。
在vue里,所有的vue实例都是组件

组件其实也是一个vue实例,因此它在定义时也会接收:data、methods、生命周期函等

不同的是组件不会与页面的元素綁定,否则就无法复用了,因此没有el属性。
但是组件渲染需要html模板,所以增加了template属性,值就是HTML模板
全局组件定义完毕,任何vue实例都可以直接在HTML中通过组件名称来使用组了
data必须是一个函数,不再是一个对象。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>

    <div id="app">
        <button v-on:click="count++">我被点击了 {{count}} 次</button>

        <counter></counter>
        <counter></counter>
        <counter></counter>
        <counter></counter>
        <counter></counter>

        <button-counter></button-counter>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>


    <script>
        //1、全局声明注册一个组件
        Vue.component("counter", {
            template: `<button v-on:click="count++">我被点击了 {{count}} 次</button>`,
            data() {
                return {
                    count: 1
                }
            }
        });

        //2、局部声明一个组件
        const buttonCounter = {
            template: `<button v-on:click="count++">我被点击了 {{count}} 次~~~</button>`,
            data() {
                return {
                    count: 1
                }
            }
        };

        new Vue({
            el: "#app",
            data: {
                count: 1
            },
            components: {
                'button-counter': buttonCounter
            }
        })
    </script>
</body>

</html>

生命周期钩子函数
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <span id="num">{{num}}</span>
        <button @click="num++">赞!</button>
        <h2>{{name}},有{{num}}个人点赞</h2>
    </div>

    <script src="../node_modules/vue/dist/vue.js"></script>
    
    <script>
        let app = new Vue({
            el: "#app",
            data: {
                name: "张三",
                num: 100
            },
            methods: {
                show() {
                    return this.name;
                },
                add() {
                    this.num++;
                }
            },
            beforeCreate() {
                console.log("=========beforeCreate=============");
                console.log("数据模型未加载:" + this.name, this.num);
                console.log("方法未加载:" + this.show());
                console.log("html模板未加载:" + document.getElementById("num"));
            },
            created: function () {
                console.log("=========created=============");
                console.log("数据模型已加载:" + this.name, this.num);
                console.log("方法已加载:" + this.show());
                console.log("html模板已加载:" + document.getElementById("num"));
                console.log("html模板未渲染:" + document.getElementById("num").innerText);
            },
            beforeMount() {
                console.log("=========beforeMount=============");
                console.log("html模板未渲染:" + document.getElementById("num").innerText);
            },
            mounted() {
                console.log("=========mounted=============");
                console.log("html模板已渲染:" + document.getElementById("num").innerText);
            },
            beforeUpdate() {
                console.log("=========beforeUpdate=============");
                console.log("数据模型已更新:" + this.num);
                console.log("html模板未更新:" + document.getElementById("num").innerText);
            },
            updated() {
                console.log("=========updated=============");
                console.log("数据模型已更新:" + this.num);
                console.log("html模板已更新:" + document.getElementById("num").innerText);
            }
        });
    </script>
</body>

</html>                                                                                                                                                  


使用Vue脚手架进行开发
全局安装webpack
1 npm install webpack -g
全局安装vue脚手架
2 npm install -g @vue/cli-init
3 初始化vue项目
vue init webpack appname:vue脚手架使用webpack模板初始化一个appname项目
4 启动vue项目
项目的package.json中有scripts,代表我们能运行的命令
npm start = npm run dev: 启动项目
npm run build:将项目打包

使用element-ui
推荐使用 npm 的方式安装,它能更好地和 webpack 打包工具配合使用。
npm i element-ui -S

在 main.js 中写入以下内容:
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

1.安装vue

准备工作:
1、安装文档。我们选用npm安装:https://cn.vuejs.org/v2/guide/installation.html#NPM
创建一个vue2文件夹
npm init -y【表示该项目是npm管理】

2、安装最新稳定版
npm install vue

3、创建index.html,引入vue.js
<script src="./node_modules/vue/dist/vue.js"></script>

4、在VS CODE中安装Vue 2 Snippets语法提示 插件

5、在浏览器中安装一个 vue工具包【https://www.jianshu.com/p/79eefcc5418f】
Vue-Devtools.zip  解压,google浏览器 更多工具-》扩展程序-》开发者模式-》加载已解压的扩展程序
作用:检查vue实例的data数据

C:\Users\Administrator\AppData\Local\Google\Chrome\User Data\Default\Extensions\nhdogjmejiglipccpnnnanhbledajbpd\5.3.4_0,修改"persistent": true,

在这里插入图片描述

2.安装webpack模板

1、全局安装webpack【能把项目打包】
	npm install webpack -g
	细节:cmd右键取消快速编辑模式
	
2、安装vue脚手架【模块化项目】
	npm install -g @vue/cli-init【后面init 失败,选择下面一条语句成功】
	解决方法一:cnpm install -g vue-cli
	解决方法二:https://blog.csdn.net/zhumizhumi/article/details/89875666
		查找vue.cmd,将文件夹添加到环境变量Path中
		
3、vue脚手架初始化一个叫vue-demo以webpack为模板的应用
	vue init webpack vue-demo【https://www.cnblogs.com/yuesebote/p/13750140.html】

3.安装elemnet-ui

https://element.eleme.cn/#/zh-CN/component/installation
1.npm i element-ui -s

ES全文检索

1.安装ES

1、下载镜像文件
docker pull elasticsearch:7.4.2

2、创建目录,作为挂载目录
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data

3.允许任何ip访问
命令含义解释:将配置写入elasticsearch.yml文件中
echo "http.host:0.0.0.0">> /mydata/elasticsearch/config/elasticsearch.yml

4.打开9200端口
firewall-cmd --add-port=9200/tcp --permanent


root用户下关闭防火墙:centos6:chkconfig iptables off
centos7:systemctl stop firewalld.service

5.解决BUG,elasticsearch自动关闭
docker logs elasticsearch【查看日志,data文件夹权限不够】
docker logs cb8【查看日志,使用id查看】
修改其他用户权限也是 rwx
解决:chmod -R 777 /mydata/elasticsearch/【-R递归修改任何组任何角色都是rwx】

6.根据镜像启动一个容器
	1)容器名字,暴露两个端口。9200:HTTP请求,9300:分布式集群下各节点通信端口
	2)单节点运行
	3)指定内存,默认占用所有
	4)挂载 -v,可以直接在容器外部修改配置,装插件
	5)-d使用镜像: elasticsearch:7.4.2
docker run --name elasticsearch -p 9200:9200 -p9300:9300 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx128m" \
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
--privileged=true \
-d elasticsearch:7.4.2

7.自动启动
docker update elasticsearch --restart=always

8.重启
docker restart elasticsearch
http://192.168.245.124:9200/

在这里插入图片描述

1.1.指定一个更大内存的es

注:
	移除老的容器数据不会遗失,因为挂载了本地目录,当启动新的容器时挂在到相同目录下即可
1.停止已启动的es容器
docker stop elasticsearch

2.删除容器
docker rm elasticsearch

2、创建目录,作为挂载目录
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data

3.允许任何ip访问
命令含义解释:将配置写入elasticsearch.yml文件中
echo "http.host: 0.0.0.0">> /mydata/elasticsearch/config/elasticsearch.yml

4.打开9200端口
firewall-cmd --add-port=9200/tcp --permanent


root用户下关闭防火墙:centos6:chkconfig iptables off
centos7:systemctl stop firewalld.service

解决:chmod -R 777 /mydata/elasticsearch/【-R递归修改任何组任何角色都是rwx】

3.启动新容器,分配512M内存
docker run --name elasticsearch -p 9200:9200 -p9300:9300 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms64m -Xmx512m" \
-v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \
-v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
--privileged=true \
-d elasticsearch:7.4.2

4.自动启动
docker update elasticsearch --restart=always

5.重启
docker restart elasticsearch

2.安装Kibana(可视化检索数据)

1、下载镜像文件
docker pull kibana:7.4.2

2.根据镜像启动一个容器
	1)-e elasticsearch.url 表示设置启动参数,主机地址
	2)-p 端口映射
	3)-d 使用的镜像
docker run --name kibana -e ELASTICSEARCH_URL=http://192.168.245.124:9200 -p 5601:5601 \
-d kibana:7.4.2
【步骤2正确语句写法:以上写法是为了演示步骤4解决异常
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.56.10:9200 -p 5601:5601 \
-d kibana:7.4.2】


3.访问192.168.56.10:5601
Kibana server is not ready yet

4.解决异常【docker run语句】
	1)docker logs 容器ID
	2)docker exec -it kibana /bin/bash
	3)vi /usr/share/kibana/config/kibana.yml
	修改 elasticsearch.hosts: [ "http://192.168.56.10:9200" ]

5.修改kibana为中文
	1)docker exec -it kibana /bin/bash
	2)vi /usr/share/kibana/config/kibana.yml
	3)增加以下配置:
	i18n.locale: "zh-CN"

6.docker update kibana --restart=always

7.docker restart kibana

3.安装ik分词器

1.下载对应版本分词器
选择对应es版本安装:https://github.com/medcl/elasticsearch-analysis-ik/releases?after=v7.6.0
下载7.4.2
不能使用默认 elasticsearch-plugin install xxx.zip
2、具体步骤
	1)docker exec -it elasticsearch /bin/bash【可以直接在外部挂载的文件夹下】
		cd /mydata/elasticsearch/plugins
	2)安装wget
		yum install wget
	3)wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.4.2/elasticsearch-analysis-ik-7.4.2.zip
	4)创建ik文件夹,解压: unzip 
	5)rm -rf *.zip
	6)修改权限 chmod -R 777 ik/
	7)检查ik是否装好:docker exec -it elasticsearch /bin/bash
					cd /bin
	8)重启elasticsearch

ik分词器安装地址: elasticsearch-analysis-ik-7.4.2.zip

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值