乐趣区

关于java:JTday15

1、Redis 集群阐明

1.1 分片、哨兵有哪些毛病

1、分片毛病:分片的次要的性能是实现内存的扩容, 然而没有高可用的成果
2、哨兵毛病:数据没有扩容, 哨兵自身没有高可用机制
需要:既能够实现内存数据的扩容, 同时实现高可用机制(不必第三方)

1.2 Redis 集群搭建


复制 Redis 的 redis.conf
命令:cp redis.conf cluster/7000/

批改 redis.conf 文件

1、正文本地绑定 IP 地址

2、敞开保护模式

3、批改端口号

4、启动后盾启动

5、批改 pid 文件

6、批改长久化文件门路

7、设定内存优化策略

8、敞开 AOF 模式

9、开启集群配置

10、开启集群配置文件

11、批改集群超时工夫

12、7000 里的 redis.conf 复制到 7001、7002、7003、7004、7005
13、批改

把文件 7001 里的 redis.conf 文件里的 7000 批改为 7001
把文件 7002 里的 redis.conf 文件里的 7000 批改为 7002
把文件 7003 里的 redis.conf 文件里的 7000 批改为 7003
把文件 7004 里的 redis.conf 文件里的 7000 批改为 7004
把文件 7005 里的 redis.conf 文件里的 7000 批改为 7005

把文件内容里的 7000 全副改为 7002
命令::%s/7000/7002/g

1、首先敞开所有的 Redis 服务器

2、查看配置文件编辑是否正确
3、删除多余的配置文件

4、重启 redis 服务器

5、搭建 redis 集群
执行命令:

redis-cli --cluster create --cluster-replicas 1 192.168.126.129:7000 192.168.126.129:7001 192.168.126.129:7002 192.168.126.129:7003 192.168.126.129:7004 192.168.126.129:7005


编辑开启服务器脚本

开启服务 命令:sh start.sh

编辑敞开服务器脚本

命令:sh stop.sh

1.3 集群入门案例

@Test
    public void testCluster(){Set<HostAndPort> sets = new HashSet<>();
        sets.add(new HostAndPort("192.168.126.129", 7000));
        sets.add(new HostAndPort("192.168.126.129", 7001));
        sets.add(new HostAndPort("192.168.126.129", 7002));
        sets.add(new HostAndPort("192.168.126.129", 7003));
        sets.add(new HostAndPort("192.168.126.129", 7004));
        sets.add(new HostAndPort("192.168.126.129", 7005));
        JedisCluster jedisCluster = new JedisCluster(sets);
        jedisCluster.set("jedis", "集群赋值");
        System.out.println(jedisCluster.get("jedis"));
    }

1.4 面试题

1、redis 集群中一共能够存储 16384 个 key???
不对的
答:16384 只是槽位的数量, 只负责布局这个数据归谁治理的问题, 至于数据如何存储, 是由 redis 内存决定的

2、redis 集群中最多能够有多少台主机
16384 台主机

3、redis 中如果遇到多线程操作, 是否有线程安全性问题?
没有
因为:redis 服务器是单过程线程操作, 每次操作都是由一个线程执行, 所以不会有线程安全性问题

4、redis 如何实现内存数据的优化?
LRU、LFU、随机算法、TTL

1.5 SpringBoot 整合 redis 集群

1.5.1 编辑 properties 文件

阐明:将 redis 集群的节点写入 pro 配置文件中

#redis 集群配置
redis.nodes=192.168.126.129:7000,192.168.126.129:7001,192.168.126.129:7002
,192.168.126.129:7003,192.168.126.129:7004,192.168.126.129:7005

1.5.2 编辑配置类

package com.jt.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import java.util.HashSet;
import java.util.Set;
@Configuration// 标识我是配置类
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig {@Value("${redis.nodes}")
    private String nodes;                                             //node,node,node
 // 实现 redis 集群操作
 @Bean
 public JedisCluster jedisCluster(){Set<HostAndPort> nodeSet=new HashSet<>();
        String[] nodeArray=nodes.split(",");
        for (String node:nodeArray) {                                //host:port
 String host=node.split(":")[0];
            int port=Integer.parseInt(node.split(":")[1]);
            nodeSet.add(new HostAndPort(host,port));
        }
        return new JedisCluster(nodeSet);
    }
     /*
 SpringBoot 整合 Redis 分片, 本质:ShardedJdeis 对象, 交给容器治理
 *///    @Bean
//    public ShardedJedis shardedJedis(){//        List<JedisShardInfo> shards=new ArrayList<>();
//        String[] nodeArray=nodes.split(",");                  // 截取
//        for (String node:nodeArray) {                                //node=ip:port
//            String host=node.split(":")[0];                   // 截取
//            int port=Integer.parseInt(node.split(":")[1]);    // 转化为 int 类型
//            // 筹备分片节点信息
//            JedisShardInfo info=new JedisShardInfo(host,port);
//            shards.add(info);
//        }
//        return new ShardedJedis(shards);
//    }
//    @Value("${redis.host}")
//    private String host;
//    @Value("${redis.port}")
//    private Integer port;
//
//    @Bean
//    public Jedis jedis(){//        return new Jedis(host,port);
//    }
}

1.5.3 编辑 AOP 配置

在 AOP 中注入 Redis 缓存对象

package com.jt.aop;
import com.jt.anno.CacheFind;
import com.jt.util.ObjectMapperUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisCluster;
import java.util.Arrays;
@Aspect // 标识我是一个切面
@Component // 交给 spring 容器治理
public class CacheAOP {
    @Autowired
 private JedisCluster jedis;                   // 实现集群的注入
 //private ShardedJedis jedis;                 // 实现分片对象的注入
 //private Jedis jedis;
 /* 注意事项:当有多个参数时,joinPoint 参数必须位列第一位
 需要:1、筹备 key= 注解的前缀 + 用户的参数
 2、从 redis 中获取数据
 有:从缓存中获取数据之后, 间接返回值
 没有:查询数据库之后再次保留到缓存中即可
 办法:动静获取注解的类型, 看上去是注解的名称, 然而本质是注解的类型, 只有切入点表达式满足条件
 则会传递注解对象类型
 */
 @Around("@annotation(cacheFind)")
    public Object around(ProceedingJoinPoint joinPoint, CacheFind cacheFind) throws Throwable {
        Object result=null;                                             // 定义返回值对象
 String preKey=cacheFind.preKey();                               // 获取 key
 String key=preKey+"::"+ Arrays.toString(joinPoint.getArgs());   // 拼接 key
 //1、校验 redis 中是否有数据
 if(jedis.exists(key)){
            // 如果数据存在, 须要从 redis 中获取 json 数据, 之后间接返回
 String json=jedis.get(key);                                 // 获取该数据
 //1、获取办法对象 2、获取办法的返回值类型
 MethodSignature methodSignature= (MethodSignature) joinPoint.getSignature();//MethodSignature 该办法里有获取该办法的返回值类型
 //2、获取返回值类型
 Class returnType=methodSignature.getReturnType();           // 获取返回值类型
 result=ObjectMapperUtil.toObject(json,returnType);          // 将 JSON 转化为对象
 System.out.println("AOP 查问缓存");
        }else {
            // 代表没有数据, 须要查询数据库
 result=joinPoint.proceed();
            // 将数据转化为 JSON
 String json= ObjectMapperUtil.toJSON(result);               // 转化为 JSON
 if (cacheFind.seconds()>0){jedis.setex(key,cacheFind.seconds(),json);              // 如果有设定工夫, 则执行
 }else{jedis.set(key, json);                                   // 没有设定工夫执行
 }
            System.out.println("AOP 查询数据库");
        }
        return result;                                                  // 返回该数据
 }
/* @Around("@annotation(com.jt.anno.CacheFind)")
 public Object around(ProceedingJoinPoint joinPoint) throws Throwable { //1. 获取指标对象的 Class 类型
 Class targetClass = joinPoint.getTarget().getClass(); //2. 获取指标办法名称
 String methodName = joinPoint.getSignature().getName(); //3. 获取参数类型
 Object[] argsObj = joinPoint.getArgs(); Class[]  argsClass = null; //4. 对象转化为 class 类型
 if(argsObj.length>0){argsClass = new Class[argsObj.length]; for(int i=0;i<argsObj.length;i++){argsClass[i] = argsObj[i].getClass();} } //3. 获取办法对象
 Method targetMethod = targetClass.getMethod(methodName,argsClass);
 //4. 获取办法上的注解
 if(targetMethod.isAnnotationPresent(CacheFind.class)){CacheFind cacheFind = targetMethod.getAnnotation(CacheFind.class); String key = cacheFind.preKey() + "::" +Arrays.toString(joinPoint.getArgs()); System.out.println(key); }
 Object object = joinPoint.proceed(); System.out.println("盘绕开始后");
 return object; }*/
 // 切面 = 切入点表达式 + 告诉办法
 //@Pointcut("bean(itemCatServiceImpl)")
 //@Pointcut("within(com.jt.service.ItemCatServiceImpl)") //@Pointcut("within(com.jt.service.*)")// .* 一级包门路 ..* 所有子孙后代包
 //@Pointcut("execution(返回值类型 包名. 类名. 办法名(参数列表))")
 //@Pointcut("execution(* com.jt.service.*.*(..))") // 正文:返回值类型任意类型 在 com.jt.service 下的所有子孙类  以 add 结尾的办法, 任意参数类型
//    public void pointCut(){//}
 /*
 需要:1、须要获取以后指标办法的门路
 2、获取指标办法的参数
 3、获取指标办法的名称
 */
//    @Before("pointCut()")
//    public void before(JoinPoint joinPoint){//        String classNamePath=joinPoint.getSignature().getDeclaringTypeName();
//        String methodName=joinPoint.getSignature().getName();
//        Object[] args=joinPoint.getArgs();
//        System.out.println("办法的门路"+classNamePath);
//        System.out.println("办法的名称"+methodName);
//        System.out.println("办法的参数"+ Arrays.toString(args));
//    }
//
//    @Around("pointCut()")
//    public Object around(ProceedingJoinPoint joinPoint){
//        try {//            System.out.println("盘绕告诉开始");
//            Object obj=joinPoint.proceed();            // 如果有下一个告诉, 就执行下一个告诉, 如果没有就执行指标办法(业务办法)
//            System.out.println("盘绕告诉完结");
//            return obj;
//        } catch (Throwable throwable) {//            throwable.printStackTrace();
//            throw new RuntimeException(throwable);
//        }
//    }
}

2、京淘前台我的项目搭建

2.1 京淘架构图设计

2.2 JT-WEB 我的项目创立

2.2.1 创立 JT-WEB 服务器

2.2.2 增加继承、依赖、插件

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <!-- 我的项目坐标 -->
 <modelVersion>4.0.0</modelVersion>
    <artifactId>jt-web</artifactId>
    <!-- 打 war 包 -->
 <packaging>war</packaging>
    <!-- 父级工程 -->
 <parent>
        <artifactId>jt2007</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <!-- 增加依赖项 -->
 <dependencies>
        <dependency>
            <groupId>com.jt</groupId>
            <artifactId>jt-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <!-- 增加 maven 插件 -->
 <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2.2.3 导入动态资源文件

阐明: 将课前材料中的文件 src 目录导入到 jt-web 中

2.2.4 对于主启动类阐明

阐明:jt-web 服务器启动时会加载数据源的自动化配置, 然而 web 服务器没有配置数据源, 所以报错

启动类上增加数据源启动

2.2.5 配置工作目录

2.3 域名反向代理

需要:要求用户通过 http://www.jt.com 拜访 localhost:8092 服务器

2.3.1 批改 hosts 文件

2.3.2 批改 Nginx 配置文件

# 配置前台服务器
    server {
        listen 80;
        server_name www.jt.com;

        location / {proxy_pass http://localhost:8092;}
    }

批改之后, 重启 nginx 服务器

2.3.3 页面成果展示

2.4 谷歌浏览器禁用 HTTPS

键入地址:

chrome://net-internals/#hsts:


批改实现之后, 先清空缓存之后重启浏览器

2.5 开启后缀类型匹配

阐明: 因为京东商城的商品展示时通过
url:https://item.jd.com/100213774…

package com.jt.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfigurer implements WebMvcConfigurer{
   
   // 开启匹配后缀型配置
 @Override
 public void configurePathMatch(PathMatchConfigurer configurer) {configurer.setUseSuffixPatternMatch(true);
   }
}

URL 地址小结:
1、http://www.jt.com/index 该申请会被 Controller 进行拦挡
2、http://www.jt.com/index.html 该申请默认条件下示意获取动态资源文件, 不会被拦挡
个别条件下:Controller 只拦挡前缀类型的申请. 如果须要拦挡后缀类型的申请须要独自配置

3、登录注册页面跳转

3.1 实现通用的页面跳转

url1:http://www.jt.com/user/login…. 跳转页面 login.jsp
url2:http://www.jt.com/user/regist… 跳转页面 register.jsp
需要: 是否利用一个 Controller 办法. 实现通用页面的跳转?

package com.jt.config.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("user")
public class UserController {
    /*
 实现用户登录、注册页面的跳转
 url1:   http://www.jt.com/user/login.html 跳转页面 login.jsp
 url2:   http://www.jt.com/user/register.html 跳转页面 register.jsp
 */ 
    @RequestMapping("/{moduleName}")
    public String module(@PathVariable String moduleName){return moduleName;}
}

3.2 伪动态

伪动态是绝对实在动态来讲的,通常咱们 为了加强搜索引擎的敌对性 ,都将文章内容生成动态页面,然而有的敌人为了实时的显示一些信息。或者还想使用动静脚本解决一些问题。不能用动态的形式来展现网站内容。然而这就损失了对搜索引擎的敌对性。怎么样在两者之间找个两头办法呢,这就产生了 伪动态技术。伪动态技术是指展现进去的是以 html 一类的动态页面模式,但其实是用 ASP 一类的动静脚本来解决的。

总结:以.html 结尾的一种动静页面的模式

作业

1、预习什么是跨域?

1、JSONP
2、CORS 形式
退出移动版