Git:
Basic Commands
1 git init ------ 初始化本地git仓库
2 git add ------ 添加文件
3 git status ------ 查看状态
4 git commit ------ 提交
5 git push ------ 推送到仓库
6 git pull ------ 从远程仓库拉取数据
7 git clone ------ 从远程仓库拷贝数据
具体操作:
第一步------创建文件夹并进入
第二步------git --version
第三步------在该文件夹中创建文件 index.html
第四步------git init (设置本地仓库)
第五步------git config --global user.name ‘WangHe’
第六步------git config --global user.email ‘13652175995@163.com’
第七步------git add index.html
第八步------git status
第九步------git add *.html
第十步------git rm -cached index.html
第十一步----git add .
第十二步----git commit
第十三步----git commit -m “change add.js” (linux用单引号)
Vue:
1 初始化Vue对象------ new Vue({
el:"#vue-app",
data:{
name:“米斯特王”
}
});
{{name}}
2 添加方法------ new Vue({
el:"#vue-app",
data:{
name:“米斯特王”
},
methods:{
greet:function (time) {
return "good "+time+“Morning”+this.name
}
}
});
{{greet(“afternoon”)}}
3 绑定属性(v-bind,v-html)------ website:"http://www.baidu.com",
websiteTeg:"<a href='http://www.tmooc.cn'>达内学生系统</a>"
<div id="vue-app">
<a v-bind:href="website">百度一下,你就不知道</a>
<input type="text" v-bind:value="name">
<p v-html="websiteTeg"></p>
</div>
4 绑定事件------new Vue({
el:"#app-div",
data:{
age:0,
x:0,
y:0
},
methods:{
add:function (a) {
console.log(a)
this.age = this.age+a;
},
sub:function (b) {
this.age = this.age-b;
},
getXY:function (event) {
this.x = event.screenX;
this.y = event.screenY;
}
}
})
<div id="app-div">
<h1>{{age}}</h1>
<button v-on:click="add(1)">加一岁</button>
<button v-on:click="sub(1)">减一岁</button>
<button v-on:dblclick="add(10)">加十岁</button>
<button v-on:dblclick="sub(10)">减十岁</button>
<div id="xycss" v-on:mousemove="getXY">{{x}},{{y}}</div>
</div>
5.事件修饰符
1 <button v-on:click.once="add(1)">加一岁</button>----once 让鼠标只能单击一次
2 <a v-on:click.prevent="alert" href="http://www.taobao.com">淘一下</a>----prevent 让超链接不跳转对应网址
3 <span v-on:mousemove.stop="">stop move</span>----stop 让鼠标移动事件在指定位置失效
4 event.stopPropagation()----该方法也是让鼠标移动事件在指定位置失效(需要在js中定义方法调用)
6.键盘事件及键值修饰符
1 <input type="text" v-on:keyup="inputName"/>----输入就调方法
2 <input type="text" v-on:keyup.enter="inputName"/>----输入后,按enter调方法
3 <input type="text" v-on:keyup.alt.enter="inputAge"/>---输入后,按alt+enter调方法
7.双向事件绑定
data:{
name:"",
age:""
}
1 <input ref="inputName" type="text" v-on:keyup="inputName"/>---- ref="inputName" 设置ref属性
inputName:function () {
this.name =this.$refs.inputName.value;
}
2 <input ref="inputAge" type="text" v-model="age"/>---- v-model属性,用于将变量赋值给变量
8.计算属性
1 普通属性(缺点会调用所有方法)
methods:{
aAddAge:function () {
console.log("a add age");
return this.a+this.age;
},
bAddAge:function () {
console.log("b add age");
return this.b+this.age;
}
<div id="app-div">
<h1>普通属性</h1>
<button v-on:click="a++">add to a</button>
<button v-on:click="b++">add to b</button>
<p>A - {{a}}</p>
<p>B - {{b}}</p>
<br/><br/><br/>
<span>{{aAddAge()}}</span>
<span>{{bAddAge()}}</span>
</div>
2 计算属性:(优点只调用当前方法)
computed:{
/*同上*/
}
<span>{{aAddAge}}</span> ------aAddAge和bAddAge去掉后面小括号
<span>{{bAddAge}}</span>
9.动态绑定Css样式
.aaa{
width:50px;
height:50px;
background-color:red;
}
span{
background-color:green;
}
.bbb{
margin-left:50px;
}
new Vue({
el:"#app-div",
data:{
aaa:false,
bbb:false
},
computed:{
compClasses:function () {
return {aaa:this.aaa,bbb:this.bbb}
}
}
})
<div id="app-div">
<h1>动态绑定css样式1</h1>
<div v-on:click="aaa=!aaa">变色
<!--<span v-bind:class="{aaa:aaa}">aaa</span>-->
</div>
<h2>动态绑定css样式2</h2>
<button v-on:click="aaa=!aaa">变色</button>
<button v-on:click="bbb=!bbb">移动</button>
<span v-bind:class="compClasses">aaa</span>
</div>
10.v-if的使用(v-show和v-if的区别是v-show仅仅是隐藏不显示的标签)
<button v-on:click="error=!error">404</button>
<button v-on:click="scusess=!scusess">200</button>
<!--<p v-if="error">页面不存在</p>-->
<!--<p v-else-if="scusess">成功进入页面</p>-->
<p v-show="error">页面不存在</p>
<p v-show="scusess">成功进入页面</p>
11.v-for的使用
data:{
characters:["zs","ls","ww"],
users:[{"name":"迪丽热巴","age":10},{"name":"古力娜扎","age":20},{"name":"欧阳娜娜","age":30}]
}
<h1>v-for的使用</h1>
<ul v-for="character in characters">
<li>{{character}}</li>
</ul>
<div v-for="user in users">
{{user.name}}-{{user.age}}
</div>
<div v-for="(user,index) in users">
<h1>{{index+1}}.{{user.name}}-{{user.age}}</h1>
</div>
<template v-for="(user,index) in users">
<h1>{{index+1}}.{{user.name}}-{{user.age}}</h1>
</template>
<template v-for="(user,index) in users" key="index"> --- (若不写key值报错,则采用这种方式即可)
<div v-for="(val,key) in user">
<h2>{{index+1}}.{{key}}->{{val}}</h2>
</div>
</template>
12.实例化多个vue对象
one = new Vue({
el:"#vue-app",
data:{
name:"第一个vue对象"
},
methods:{
},
computed:{
greet:function () {
return "大家好,我是第一个Vue,请多关照呦!"
}
}
}),
two = new Vue({
el:"#vue-app2",
data:{
name:"第二个vue对象"
},
methods:{
renameOne:function () {
one.name="我改名为古力娜扎"
}
},
computed:{
greet:function(){
return"大家好,我是第二个Vue,请多关照呦!"
}
}
})
<div id="vue-app">
<h1>{{name}}</h1>
<p>{{greet}}</p>
</div>
<div id="vue-app2">
<h1>{{name}}</h1>
<p>{{greet}}</p>
<button v-on:click="renameOne">改名</button>
</div>
13.初识组件的应用(公共部分可用组件抽取)
Vue.component("greeting",{
template:'<p>{{name}}:大家好这是我女朋友@关晓彤' +
'<button v-on:click="rename">改名</button></p>',
data:function () {
return {
name:"鹿晗"
}
},
methods:{
rename:function () {
this.name="吴亦凡"
}
}
})
new Vue({
el:"#vue-app",
}),
new Vue({
el:"#vue-app2",
})
<div id="vue-app">
<greeting></greeting>
</div>
<div id="vue-app2">
<greeting></greeting>
</div>
14.vue搭建脚手架CLI
第一步------node -v
第二步------npm -v
第三步------npm install --global vue-cli
第四步------vue --version
第五步------进入新建文件夹projects cd C:\Users\Administrator\Desktop\vue\projects
第六步------vue init webpack vue-playlist
第七步------no no no no 选择npm
第八步------ 启动脚手架,端口8080 cd vue-playlist
npm run dev
15.vue组件嵌套
全局组件:
main.js里添加 import Users from './components/users' Vue.component("users",Users)
app.vue里引入对应<users></users>标签
局部组件(常用):
App.vue里添加 import Users from './components/users' components:{"users":Users} <users></users>标签
16.vue组件css作用域
<style></style>------全局作用域
<style scoped></style>------局部作用域
17.Vue组件之间属性传值
第一步------在组件的html里绑定自定义属性
<app-users v-bind:users="users"></app-users>
第二步------第一种 props:["users"]
第二种 props:{
users:{
type:Array,
required:true
}
}
18.Vue传值和传引用
1 传值:各个子组件之间不影响,如String boolean等
2 传引用:各个子组件之间用的是一个对象,改变其中一个组件对象,其他组件也会改变,有两种:Array Object
19.Vue事件传值(子向父组件传值)
子组件:
methods:{ ---点击事件方法
titleChanged:function () {
this.$emit("titleChanged","子向父传值")
}
}
父组件:
<app-header v-on:titleChanged="updateTitle($event)" v-bind:title="title"></app-header>
methods:{
updateTitle:function (title) {
this.title=title
}
}
20.Vue生命周期(钩子函数,和methods平级)
beforeCreate:function () {
alert("组件实例化之前执行的函数")
},
created:function () {
alert("组件实例化完毕,但页面还未显示")
},
beforeMount:function () {
alert("组件挂载前,页面仍未展示,但虚拟dom已经配置")
},
mounted:function () {
alert("组件挂载后,此方法执行后,页面显示")
},
beforeUpdate:function() {
alert("组件更新前,页面仍未更新,但虚拟dom已经配置")
},
updated:function () {
alert("组件更新,此方法执行后,页面显示")
},
beforeDestroy:function() {
alert("组件销毁前")
},
destroyed:function() {
alert("组件销毁")
}
21.Vue路由和Http
路由:
第一步------安装路由模块 npm install vue-router --save-dev
第二步------main.js中引入路由模块 import VueRouter from 'vue-router'
第三步------用一下 Vue.use(VueRouter)
第四步------配置路由 const router = new VueRouter({
routes:[
{path:"/",component:Home },
{path:"/helloworld",component:HelloWorld }
],
mode:"history"
})
第五步------App.vue页面天加标签 <router-view></router-view>
第六步------跳转页面(不能用a,那样会整个页面跳转) <li><router-link to="/">Home</router-link></li>
<li><router-link to="/helloworld">helloworld</router-link></li>
Http:
第一步------安装http模块 npm install vue-resource --save-dev
第二步------main.js中引入http模块 import VueResource from 'vue-resource'
第三步------用一下 Vue.use()
第四步------调用接口获取数据即可 created:function () {
this.$http.get("http://jsonplaceholder.typicode.com/users").then((data)=>{
this.users = data.body
});
}
一(1) java
idea快捷键
(1) ctrl + alt +B 查看接口实现类
(2) alt+left/right 切换文件
Api方法
(1) String------length():获取字符串长度
charAt(int index):获取指定位置的字符
equals():判断两个字符串的内容是否相同,相同返回true
indexOf(String str):查找子串的起始位置下标,没有返回 -1
indexOf(String str, int start):从start 位置向后找
lastIndexOf(String str):从后向前找获取指定字符串的位置
substring(int begin):截取子串,指定开始位置一直到结束为止都会被截取到
substring(int begin,int end):截取子串,[begin, end) 指定开始位置和结束位置
(2) ArrayList------底层是用数组实现的存储,特点: 查询效率高,增删效率低,线程不安全
一(2) Java基础知识
(1) 台球小游戏:
----------------------------------------------------------------------------------------------------
import javax.swing.;
import java.awt.;
public class BallGame2 extends JFrame {
Image ball = new ImageIcon(ClassLoader.getSystemResource("images/ball.png")).getImage();
Image desk = new ImageIcon(ClassLoader.getSystemResource("images/desk.jpg")).getImage();
double x = 100;//小球的横坐标
double y = 100;//小球的纵坐标
double degree = 3.14/3;//弧度(60度)
boolean right = true;
public void paint(Graphics g) {
System.out.println("--------");
g.drawImage(desk,0,0, null);
g.drawImage(ball,(int)x,(int)y,this);
x = x+10*Math.cos(degree);
y = y+10*Math.sin(degree);
if(y>500-40-30 || y<80){
degree=-degree;
}
if( x>780 || x<50){
degree=3.14-degree;
}
}
void launchFrame(){
setSize(856,500);
setLocation(200,200);
setVisible(true);
while (true){
repaint();
try {
Thread.sleep(40);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
BallGame2 ballGame = new BallGame2();
ballGame.launchFrame();
}
}
----------------------------------------------------------------------------------------------------
(2) 飞机小游戏(略)
(3) Thread
1 静态代理模式
public class StaticProxy {
public static void main(String[] args) {
new WeddingCompany(new You()).happyMarry();
//参考 new Thread(new MyThread()).start;
}
}
interface Marry {
public void happyMarry();
}
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("你和嫦娥结婚了");
}
}
class WeddingCompany implements Marry {
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void happyMarry() {
System.out.println("布置婚房");
target.happyMarry();
System.out.println("闹洞房");
}
}
2 join方法的使用
public class JoinUse {
public static void main(String[] args) {
new Thread(new Father()).start();
}
}
class Father extends Thread{
@Override
public void run() {
System.out.println("想抽中华烟,让儿子去买烟");
Thread thread = new Thread(new Son());
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("找儿子去了");
}
System.out.println("抽上了,把零钱给儿子了");
}
}
class Son extends Thread{
@Override
public void run() {
System.out.println("儿子去了,路过游戏厅玩了10秒");
for (int i=1;i<=10;i++){
System.out.println("过了"+i+"秒");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("购买成功,带一包中华烟回家");
}
}
一() SpringBoot
springBoot分页+查询条件示例:
dao------@Query(value = “select * from tb_problem,tb_pl where id = problemid and labelid=? order by replytime desc “,nativeQuery = true)
public Page newList(String labelid, Pageable pageable);
service------ public Page findSearch(Map whereMap, int page, int size) {
Specification specification = createSpecification(whereMap);
PageRequest pageRequest = PageRequest.of(page-1, size);
return problemDao.findAll(specification, pageRequest);
}
查询条件------ private Specification createSpecification(Map searchMap) {
return new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List predicateList = new ArrayList();
// ID
if (searchMap.get(“id”)!=null && !””.equals(searchMap.get(“id”))) {
predicateList.add(cb.like(root.get(“id”).as(String.class), “%”+(String)searchMap.get(“id”)+"%"));
}
// 标题
if (searchMap.get(“title”)!=null && !"".equals(searchMap.get(“title”))) {
predicateList.add(cb.like(root.get(“title”).as(String.class), “%”+(String)searchMap.get(“title”)+"%"));
}
return cb.and( predicateList.toArray(new Predicate[predicateList.size()]));
}
};
}
controller------ @RequestMapping(value = "/waitList/{labelid}/{page}/{size}",method = RequestMethod.GET)
public Result waitList(@PathVariable String labelid,@PathVariable int page,@PathVariable int size){
Page<Problem> pageData = problemService.waitList(labelid, page, size);
return new Result(true,StatusCode.OK,"查询成功",new PageResult<Problem>(pageData.getTotalElements(),pageData.getContent()));
}
Environment------可以获取配置文件中的所有信息
@Value("${aliyun.sms.template_code}")------获取配置文件中属性
private String template_code;//模板编号
二 DOCKER命令
安装docker
步骤一:将以前下载好的Docker卸载干净, 使用如下命令:
yum remove docker-*
1
步骤二:更新该Liunx系统的内核版本,使用如下命令:
yum update
1
建议更新完之后, 重启一下系统
步骤三:继续下载安装docker(尽量使用高级管理员权限下载)使用如下命令
yum install dacker
1
步骤四:使用如下命令启动docker
systemctl start docker
1
问题解决!
如果这样安装完之后还报错, 按照这个步骤再来一遍即可
如果使用docker命令时出现如下错误:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
1
第一个原因可能是因为docker没有启动
第二个原因就是因为docker出现错误
归根结底都是docker启动问题, 解决方案还是以上步骤
安装docker 时候出现以下问题
yum -y install docker
Loaded plugins: fastestmirror
Determining fastest mirrors
- base: centos.uhost.hk
- extras: mirrors.btte.net
- updates: mirror.bit.edu.cn
base | 3.7 kB 00:00
base/primary_db | 4.7 MB 00:47
extras | 3.4 kB 00:00
extras/primary_db | 29 kB 00:00
updates | 3.4 kB 00:00
updates/primary_db | 2.5 MB 00:20
Setting up Install Process
No package docker available.
Error: Nothing to do
yum没有找到docker包,更新epel第三方软件库,运行命令:
sudo yum install epel-release
之后运行
sudo yum install docker-io
即可
安装文档 http://www.runoob.com/docker/centos-docker-install.html
启动docker------systemctl start docker
查找镜像------docker search mysql docker pull elasticsearch:5.6.8 等
安装镜像------docker pull mysql/mysql-server
制作容器(mysql)------docker run -di --name=tensquare_mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root centos/mysql-57-centos7:版本
制作容器(redis)------docker run -di --name=tensquare_redis -p 6379:6379 redis
制作容器(mongo)------docker run -di --name=tensquare_mongo -p 27017:27017 mongo
制作容器(elasticsearch)------docker run di --name=tensquare_elasticsearch -p 9200:9200 -p 9300:9300 elasticsearch:5.6.8
查看正在运行的容器------docker ps
查看所有容器------docker ps -a
启动容器------docker start id号
删除容器------docker rm id号
三 缓存使用
第一步------
org.springframework.boot
spring-boot-starter-data-redis
第二步------ yml文件中加:spring:
redis:
host: 192.168.47.141
redisAPI------查询缓存:redisTemplate.opsForValue().get(String key);
添加缓存:redisTemplate.opsForValue().set(String key,Object value);
删除缓存:redisTemplate.delete(String key);
设置缓存时间:redisTemplate.opsForValue().set(“article_”+id,article,10, TimeUnit.SECONDS);
spring自带缓存使用方法------1.主启动类加@EnableCaching;
2.查询 @Cacheable(value = “gathering”,key = “#id”);
3.修改和删除 @CacheEvict(value = “gathering”,key = “#gathering.id”)
4.弊端,不能设置缓存时间
四(1) MongoDB(了解)------1.安装配环境变量,和mysql数据库一样
2.设置服务器存储路径 mongod -dbpath=d:\data (需要提前创建data文件夹)
3.启动客户端(默认localhost) mongo (非默认则mongo ip)
常用命令(了解,属于底层原理范畴):1.创建数据库: use spitdb
2.创建表并查看: db.spit.find()
3.插入数据: db.spit.insert({content:“最近有点冷”,visits:10})
4.查询id为1的数据: db.spit.find({_id:“1”})
5.查一条记录: db.spit.findOne({userid:‘1013’})
6.分页查询: db.spit.find().limit(3);
7.修改数据: db.spit.update({_id:“2”},{KaTeX parse error: Expected 'EOF', got '}' at position 29: …umberInt(2000)}}̲) 简单查询API: …gt",1000));
//得到集合中所有文档
FindIterable documents = spit.find(bson);
添加数据API:
Map<String,Object> map = new HashMap<>();
map.put("_id",123);
map.put(“content”,“时间过的好快呀”);
map.put(“userid”,“1016”);
map.put(“visits”,100);
Document document = new Document(map);
spit.insertOne(document);
四(2) SpringDataMongoDB
依赖包------
org.springframework.boot
spring-boot-starter-data-mongodb
yml文件中加------spring:
data:
mongodb:
host: 192.168.47.141
database: spitdb
SpringDataMongoDB API------
public void thumbup(String spitId) {
//更新时每次查询数据库效率低
//Spit spit = spitDao.findById(spitId).get();
//spit.setThumbup((spit.getThumbup()==null?0:spit.getThumbup())+1);
//spitDao.save(spit);
Query query = new Query();
query.addCriteria(Criteria.where("_id").is("1"));
Update update=new Update();
update.inc("thumbup",1);
mongoTemplate.updateFirst(query,update,"spit");
}
五 ElasticSearch(1)
第一步------解压
第二步------进入bin目录,输入命令: elasticsearch 9300和9200端口都起来了即可
重启 1.ctrl+c 2.y 3.elasticsearch
第三步------检测 在浏览器输入: http://localhost:9200 出现对应json数据,即为成功
第四步------创建索引库(put请求) http://localhost:9200/tensquare_elasticsearch
第五步------添加类型(post请求) http://localhost:9200/tensquare_elasticsearch/article
提交json数据— {
“title”:“spring教程”,
“content”:“spring框架教程”
}
返回数据— {
“_index”: “tensquare_elasticsearch”,
“_type”: “article”,
“_id”: “AWu1kPC9fUfKbzZPNqi4”,
“_version”: 1,
“result”: “created”,
“_shards”: {
“total”: 2,
“successful”: 1,
“failed”: 0
},
“created”: true
}
第六步------查询所有(get请求) http://localhost:9200/tensquare_elasticsearch/article/_search
第七步------修改(put请求) http://localhost:9200/tensquare_elasticsearch/article/AWu1kPC9fUfKbzZPNqi4
提交json数据— {
“title”:“spring教程”,
“content”:“杨超越舞蹈教程”
}
返回数据— {
“_index”: “tensquare_elasticsearch”,
“_type”: “article”,
“_id”: “AWu1kPC9fUfKbzZPNqi4”,
“_version”: 2,
“result”: “updated”,
“_shards”: {
“total”: 2,
“successful”: 1,
“failed”: 0
},
“created”: false
}
第八步------根据id查询(get请求) http://localhost:9200/tensquare_elasticsearch/article/AWu1kPC9fUfKbzZPNqi4
第九步------根据字段查询(get请求) http://localhost:9200/tensquare_elasticsearch/article/_search?q=content:杨超越
第十步------分词后再模糊查询(get请求) http://localhost:9200/tensquare_elasticsearch/article/_search?q=title:s
第十一步------根据id删除(delete请求) http://localhost:9200/tensquare_elasticsearch/article/AWu1kPC9fUfKbzZPNqi4
五(2) head插件安装及使用(该插件相当于elasticsearch的图形化操作界面)
第一步------下载elasticsearch-head-master并解压
第二步------安装nodejs
第三步------安装cnpm(npm默认在国外,所有要安装国内的cnpm) npm install -g cnpm -registry=https://registry.npm.taobao.org
用 npm -v cnpm -v 检测是否安装成功
第四步------安装grunt npm install -g grunt-cli
第五步------安装依赖 cnpm install(要先进入package.json所在目录,再执行此命令)
第六步------进入head插件安装目录,启动head(默认端口9100) grunt server
第七步------访问: http://localhost:9100 进入head插件
第八步------解决跨域问题 修改elasticsearch配置文件:elasticsearch.yml,增加以下两句命令:
http.cors.enabled: true
http.cors.allow-origin: “*”
五(3) ik分词器
第一步------下载ik分词器(版本要和elasticsearch对应)并解压
第二步------直接将解压后的文件夹改名ik后,放到E:\elasticsearch-5.6.8\plugins文件夹下
第三步------重启elasticsearch
第四步------测试 (1)最小切分:http://127.0.0.1:9200/_analyze?analyzer=ik_smart&pretty=true&text=我是程序员
(2)最细切分:http://127.0.0.1:9200/_analyze?analyzer=ik_max_word&pretty=true&text=我是程序员
第五步------增加词条 (1)在E:\elasticsearch-5.6.8\plugins\ik\config文件夹下新建costum.dic文件,并设置编码为utf-8(无BOM的)
(2)在文件中写上词条,如传智播客(若不能识别,可能是系统原因,把第一行空出来,从第二行开始写词条即可)
(3)把costum.dic文件在IKAnalyzer.cfg.xml文件中声明
(4)重启elasticsearch
五(4) springboot整合elasticsearch(保存数据全过程)
第一步------添加依赖
org.springframework.data
spring-data-elasticsearch
3.0.6.RELEASE
第二步------在yml文件中添加内容 spring:
data:
elasticsearch:
cluster-nodes: 127.0.0.1:9300
第三步------创建实体类 @Document(indexName = “tensquare_article”,type = “article”)
public class Article implements Serializable {
@Id
private String id;
//是否索引,就是看该域是否能被搜索
//是否分词,就表示搜索的时候是整体匹配还是单词匹配
//是否存储,是否在页面上显示(不显示不写数据库对应字段即可)
@Field(index = true,analyzer=“ik_max_word”,searchAnalyzer=“ik_max_word”)
private String title;
@Field(index = true,analyzer=“ik_max_word”,searchAnalyzer=“ik_max_word”)
private String content;
private String state;//审核状态
}
第四步------创建Dao public interface ArticleDao extends ElasticsearchCrudRepository<Article,String> {}
第五步------创建Service @Service
public class ArticleService {
@Autowired
private ArticleDao articleDao;
public void save(Article article){
articleDao.save(article);
}
}
第六步------创建Controller @RestController
@RequestMapping("/article")
@CrossOrigin
public class ArticleController {
@Autowired
private ArticleService articleService;
@RequestMapping(method = RequestMethod.POST)
public Result save(@RequestBody Article article){
articleService.save(article);
return new Result(true, StatusCode.OK,“添加成功”);
}
}
五(5) Logstash安装与测试(Logstash是一款轻量级的日志搜集处理框架)
第一步------解压进入bin目录
第二步------在当前目录打开控制台,输入: logstash -e ‘input { stdin { } } output { stdout {} }’
第三步------控制台输入字符如 aaaaa 返回字符aaaaa即可
第四步------ MySQL数据导入Elasticsearch
(1) 在logstash-5.6.8安装目录下创建文件夹mysqletc (跟bin目录同级,名称随意)
(2) 文件夹下创建mysql.conf (名称随意) ,内容如下:
-----------------------------------------------------------------------------------------------------------
input {
jdbc {
# mysql jdbc connection string to our backup databse
jdbc_connection_string => “jdbc:mysql://192.168.47.141:3306/tensquare_article?characterEncoding=UTF8”
# the user we wish to excute our statement as
jdbc_user => “root”
jdbc_password => “root”
# the path to our downloaded jdbc driver
jdbc_driver_library => “E:/elasticsearch-logstach/logstash-5.6.8/mysqletc/mysql-connector-java-5.1.46.jar”
# the name of the driver class for mysql
jdbc_driver_class => “com.mysql.jdbc.Driver”
jdbc_paging_enabled => “true”
jdbc_page_size => “50000”
#以下对应着要执行的sql的绝对路径。
#statement_filepath => “”
statement => “select id,title,content from tb_article”
#定时字段 各字段含义(由左至右)分、时、天、月、年,全部为默认含义为每分钟都更新(测试结果,不同的话请留言指出)
schedule => " * * * *"
}
}
output {
elasticsearch {
#ESIP地址与端口
hosts => "localhost:9200"
#ES索引名称(自己定义的)
index => "tensquare"
#自增ID编号
document_id => "%{id}"
document_type => "article"
}
stdout {
#以JSON格式输出
codec => json_lines
}
}
-----------------------------------------------------------------------------------------------------------
(3) 将mysql驱动包mysql-connector-java-5.1.46.jar拷贝至D:/logstash-5.6.8/mysqletc/ 下
(4) bin目录中打开cmd执行命令: logstash -f ../mysqletc/mysql.conf
(5) 观察控制台输出,每间隔1分钟就执行一次sql查询
{"@version":"1","id":"1","@timestamp":"2019-07-04T03:25:00.282Z","title":"张三","content":"哈哈哈"}
{"@version":"1","id":"2","@timestamp":"2019-07-04T03:25:00.283Z","title":"李四","content":"吼吼吼"}
{"@version":"1","id":"3","@timestamp":"2019-07-04T03:25:00.284Z","title":"王五","content":"嘿嘿嘿"}
再次刷新elasticsearch-head的数据显示,看是否也更新了数据
五(6) Elasticsearch Docker环境下安装
第一步------下载镜像(省略) docker pull elasticsearch:5.6.8
第二步------创建容器 docker run -di --name=tensquare_elasticsearch -p 9200:9200 -p 9300:9300 elasticsearch:5.6.8
第三步------浏览器输入地址:http://192.168.184.134:9200/ 即可看到如下信息:
{
“name” : “OBa8tj0”,
“cluster_name” : “elasticsearch”,
“cluster_uuid” : “vidAckHwR3q3yOgAENxqHg”,
“version” : {
“number” : “5.6.8”,
“build_hash” : “688ecce”,
“build_date” : “2018-02-16T16:46:30.010Z”,
“build_snapshot” : false,
“lucene_version” : “6.6.1”
},
“tagline” : “You Know, for Search”
}
第四步------修改demo的application.yml
spring:
data:
elasticsearch:
cluster‐nodes: 192.168.47.141:9300
第五步------测试运行程序报错:(这是因为elasticsearch从5版本以后默认不开启远程连接,需要修改配置文件)
ERROR 14264 — [ main] .d.e.r.s.AbstractElasticsearchRepository : failed to load elasticsearch nodes :
org.elasticsearch.client.transport.NoNodeAvailableException:None of the configured nodes are available:
[{#transport#-1}{zMtsoNT0TYeD3Z_ziqtlcw}{192.168.47.141}{192.168.47.141:9300}]
第六步------进入容器(这步操作可以看到elasticsearch的安装路径): docker exec -it tensquare_elasticsearch /bin/bash 再进入config看到配置文件 elasticsearch.yml
第七步------因为容器没有vi命令,需要以文件挂载的方式创建容器才行,这样我们就可以通过修改宿主机中的某个文件来实现对容器内配置文件的修改
(1) 拷贝配置文件到宿主机:
docker cp tensquare_elasticsearch:/usr/share/elasticsearch/config/elasticsearch.yml /usr/share/elasticsearch.yml
(2) 停止和删除原来创建的容器:
docker stop tensquare_elasticsearch
docker rm tensquare_elasticsearch
(3) 重新执行创建容器命令:
docker run -di --name=tensquare_elasticsearch -p 9200:9200 -p 9300:9300 -v /usr/share/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml elasticsearch:5.6.8
(4) 修改/usr/share/elasticsearch.yml 将 transport.host: 0.0.0.0 前的#去掉后保存文件退出。其作用是允许任何ip地址访问elasticsearch .
开发测试阶段可以这么做,生产环境下指定具体的IP
(5) 重新启动 docker restart tensquare_elasticsearch (会报错,因为还需要系统调优)
(6) 系统调优(一定要细致,尽量拷贝,注意中文字符,空格也可能是中文字符)
1------修改/etc/security/limits.conf ,追加内容:
* soft nofile 65536
* hard nofile 65536
nofile是单个进程允许打开的最大文件个数 soft nofile 是软限制 hard nofile是硬限制
2------修改/etc/sysctl.conf,追加内容: vm.max_map_count=655360
限制一个进程可以拥有的VMA(虚拟内存区域)的数量
3------执行下面命令 修改内核参数马上生效 sysctl ‐p(不用执行,执行了可能出问题)
4------重新启动虚拟机,再次启动容器,发现已经可以启动并远程访问
五(7) linux下IK分词器安装
(1) 将ik文件夹上传至宿主机
(2) 在宿主机中将ik文件夹拷贝到容器内 /usr/share/elasticsearch/plugins 目录下
docker cp ik tensquare_elasticsearch:/usr/share/elasticsearch/plugins/
(3) 重新启动,即可加载IK分词器
五(8) linux下HEAD插件安装
(1) 修改/usr/share/elasticsearch.yml ,添加允许跨域配置
http.cors.enabled: true
http.cors.allow-origin: “*”
(2) 重新启动elasticseach容器
(3) 下载head镜像(此步省略)
docker pull mobz/elasticsearch-head:5
(4) 创建head容器 docker run -di --name=tensquare_header -p 9100:9100 mobz/elasticsearch-head:5
(5) 访问地址 http://192.168.47.141:9100/ 并填写连接地址 点击connent按钮
六 RabbitMQ
1 windows环境下的安装(了解)
(1) 下载并安装 Eralng 配套软件中已提供otp_win64_20.2.exe (以管理员身份运行安装)
(2) 下载并安装rabbitmq 配套软件中已提供rabbitmq-server-3.7.4.exe。双击安装,注意不要安装在包含中文和 空格的目录下!
安装后window服务中就存在rabbitMQ了,并且是启动状态
(3) 安装管理界面(插件)进入rabbitMQ安装目录的sbin目录,输入命令 rabbitmq-plugins enable rabbitmq_management
(4) 打开浏览器,地址栏输入http://127.0.0.1:15672 ,即可看到管理界面的登陆页 用户名密码都是guest
2 docker环境下的安装
(1) 下载镜像:(此步省略) docker pull rabbitmq:management
(2) 创建容器,rabbitmq需要有映射以下端口: 5671 5672 4369 15671 15672 25672
15672 (if management plugin is enabled)
15671 management监听端口
5672, 5671 (AMQP 0-9-1 without and with TLS)
4369 (epmd) epmd 代表 Erlang 端口映射守护进程
25672 (Erlang distribution)
(3) docker run -di --name=tensquare_rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 15671:15671 -p 15672:15672 -p 25672:25672 rabbitmq:management
(4) 浏览器访问 http://192.168.184.134:15672/#/ 用户名密码都是guest
3 直接模式(Direct)我们需要将消息发给唯一一个节点时使用这种模式,这是最简单的一种形式。
(1) 创建队列(在图形化客户端中创建)
(2) 创建module模块并导入依赖包
org.springframework.boot
spring-boot-starter-amqp
(3) 编写配置文件application.yml
server:
port: 8099
spring:
rabbitmq:
host: 192.168.47.141
(4) 编写启动类
(5) 编写测试类
@RunWith(SpringRunner.class)
@SpringBootTest(classes = RabbitApplication.class)
public class ProductTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void sendMsg(){
rabbitTemplate.convertAndSend("itcast","直接模式测试");
}
}
(6) 编写消息消费者类(也可以用map接收)
@Component
@RabbitListener(queues = "itcast")
public class Customer1 {
@RabbitHandler
public void getMsg(String message){
System.out.println("直接模式消费消息"+message);
}
}
(7) 先运行测试方法,再运行启动类,可以看到先向消息队列中添加了一条数据,然后取了出来,可以在控制台看发送的消息
(8) 可以改变端口,运行三个消费者,然后消费者都等待数据,再运行测试方法添加三条数据,可以发现: 数据依次给了消费者,
说明rabbit默认实现了负载均衡,好处是可以分摊服务器压力
4 分列模式(Fanout) 任何发送到Fanout Exchange的消息都会被转发到与该Exchange绑定(Binding)的所有Queue上。
(1) Exchange中添加3个队列,创建三个消费者类,启动项目
(2) 测试使用Exchange方式,代码如下:
@Test
public void sendMsgTwo(){
rabbitTemplate.convertAndSend("chuanzi","","分裂模式测试");
}
5 阿里云短信服务
(1)添加依赖
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-dysmsapi</artifactId>
<version>1.0.0‐SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>3.2.5</version>
</dependency>
(2)配置文件添加内容
aliyun:
sms:
accessKeyId: 不告诉你
accessKeySecret: 不告诉你
template_code: SMS_85735065
sign_name: 黑马
(3)创建短信工具类SmsUtil (阿里巴巴短信服务里拷贝)
(4)修改消息监听类,完成短信发送
@Component
@RabbitListener(queues = "sms")
public class SmsListener {
@Autowired
private SmsUtil smsUtil;
@Value("${aliyun.sms.template_code}")
private String template_code;//模板编号
@Value("${aliyun.sms.sign_name}")
private String sign_name;//签名
@RabbitHandler
public void sendSms(Map<String,String> map){
System.out.println("手机号:"+map.get("mobile"));
System.out.println("验证码:"+map.get("code"));
try {
smsUtil.sendSms(map.get("mobile"),template_code,sign_name,"
{\"number\":\""+ map.get("code") +"\"}");
} catch (ClientException e) {
e.printStackTrace();
}
}
}
七(1) 密码加密
第一步------导入依赖
org.springframework.boot
spring-boot-starter-security
第二步------安全配置类
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and().csrf().disable();
}
}
第三步------配置bean对象(在启动类中添加该方法)
@Bean
public BCryptPasswordEncoder bcryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
第四步------管理员密码加密
@Autowired
private BCryptPasswordEncoder encoder;
public void add(Admin admin) {
admin.setId( idWorker.nextId()+"" );
String newPassword = encoder.encode(admin.getPassword());
admin.setPassword(newPassword);
adminDao.save(admin);
}
第五步------管理员登录密码校验
(1) AdminDao增加方法定义 public Admin findByLoginname(String loginname);
(2) AdminService增加方法
public Admin findByLoginnameAndPassword(String loginname, String password){
Admin admin = adminDao.findByLoginname(loginname);
if( admin!=null && encoder.matches(password,admin.getPassword())){
return admin;
}else{
return null;
}
}
(3) AdminCtroller增加方法,如果admin不为空,则登录成功
(4) 用户密码加密同理
七(2) 微服务鉴权jwt
1 JJWT快速入门
(1) token的创建 创建maven工程,引入依赖
io.jsonwebtoken
jjwt
0.6.0
(2) 创建类CreateJwtTest,用于生成token
public class CreateJwt {
public static void main(String[] args) {
JwtBuilder jwtBuilder = Jwts.builder().setId(“666”).setSubject(“小马”).setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256,“itcast”)
.setExpiration(new Date(new Date().getTime()+60*1000))//自定义时间
.claim(“role”,“admin”);//自定义claims
System.out.println(jwtBuilder.compact());
}
}
(3) 每次运行的结果是不一样的,因为我们的载荷中包含了时间
(4) token的解析
public class ParseJwtTest {
public static void main(String[] args) {
Claims claims = Jwts.parser().setSigningKey(“itcast”).parseClaimsJws(“eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NjYiLCJzdWIiOiLlsI_pqawiLCJpYXQiOjE1NjI4MzI3NTIsImV4cCI6MTU2MjgzMjgxMiwicm9sZSI6ImFkbWluIn0.wDmOPD6zx5tUk67SBAxLQTfKtHv-tQsIBK4069xNiCw”)
.getBody();
System.out.println(“用户id:”+claims.getId());
System.out.println(“用户名:”+claims.getSubject());
System.out.println(“登录时间:”+new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(claims.getIssuedAt()));
System.out.println(“过期时间:”+new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”).format(claims.getExpiration()));
System.out.println(“用户角色:”+claims.get(“role”));
}
}
(5) 超过过期时间会引发 io.jsonwebtoken.ExpiredJwtException 异常
2 项目中应用
第一步------引入依赖jjwt
第二步------创建JwtUtil工具类
@ConfigurationProperties("jwt.config")
public class JwtUtil {
private String key ;
private long ttl ;//一个小时
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public long getTtl() {
return ttl;
}
public void setTtl(long ttl) {
this.ttl = ttl;
}
/**
* 生成JWT
*
* @param id
* @param subject
* @return
*/
public String createJWT(String id, String subject, String roles) {
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
JwtBuilder builder = Jwts.builder().setId(id)
.setSubject(subject)
.setIssuedAt(now)
.signWith(SignatureAlgorithm.HS256, key).claim("roles", roles);
if (ttl > 0) {
builder.setExpiration( new Date( nowMillis + ttl));
}
return builder.compact();
}
/**
* 解析JWT
* @param jwtStr
* @return
*/
public Claims parseJWT(String jwtStr){
return Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(jwtStr)
.getBody();
}
}
第三步------修改tensquare_user工程的application.yml, 添加配置
jwt:
config:
key: itcast//盐
ttl: 360000//过期时间
第四步------主启动类中配置bean
@Bean
public JwtUtil jwtUtil(){
return new util.JwtUtil();
}
第五步------修改AdminController的login方法
@RequestMapping(value = "/login",method = RequestMethod.POST)
public Result login(@RequestBody Map<String,String> map){
Admin admin = adminService.findByLoginnameAndPassword(map.get("loginname"), map.get("password"));
if(admin!=null){
String token = jwtUtil.createJWT(admin.getId(), admin.getLoginname(), "admin");
Map<String,Object> hmap = new HashMap<>();
map.put("token",token);
map.put("role","admin");
return new Result(true,StatusCode.OK,"登录成功",map);
}else{
return new Result(false,StatusCode.LOGINERROR,"用户名或密码错误");
}
}
第六步------使用拦截器方式实现token鉴权 添加拦截器 拦截器验证token
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Autowired
private JwtUtil jwtUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("经过了拦截器");
//拦截器只负责把请求头中包含token的令牌进行一个解析验证
String header = request.getHeader("Authorization");
System.out.println(header);
if(header!=null&&!header.equals("")){
System.out.println("1111111111111");
if(header.startsWith("Bearer ")){
String token = header.substring(7);
System.out.println(token);
try {
Claims claims = jwtUtil.parseJWT(token);
String roles = (String) claims.get("roles");
if(roles!=null && "admin".equals(roles)){
System.out.println("-----------");
request.setAttribute("claims_admin",token);
}
if(roles!=null && "user".equals(roles)){
request.setAttribute("claims_user",token);
}
}catch (Exception e){
throw new RuntimeException("令牌不正确!");
}
}
}
return true;
}
}
第七步------配置拦截器类
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
protected void addInterceptors(InterceptorRegistry registry) {
//注册拦截器要声明拦截器对象和要拦截的请求
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/**/login/**");
}
}
第八步------UserService的删除用户方法
public void deleteById(String id) {
Object token = request.getAttribute("claims_admin");
if(token==null || "".equals(token)){
throw new RuntimeException("权限不足");
}
userDao.deleteById(id);
}
第九步-----总结:
登录admin或user时创建token并发送给前台,前台得到token,如果是需要登录相关角色才能使用的功能,
则讲tocken传到后台,拦截器拦截所有请求,如果带有规定的token头则拦截,验证token,不通过则权限不足,
通过后再判断是admin还是user还是其他角色,讲tocken存在Request域中,key为具体的角色,
最后在需要角色登录的功能上获取Request域中的tocken,存在则通过,不存在则权限不足
N 面试题
1.sql语句优化------join比子查询效率高
直接写字段比写*效率高
不要全表扫描,比如!=什么什么,in not in 用 EXISTS NOT EXISTS代替(涉及到非的都属于全表扫描)