BolunWu

BolunWu 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

BolunWu 发布了文章 · 10月24日

京淘Day15

1.实现Redis集群的搭建

1.1为什么需要搭建集群

redis分片的特点:

1.可以实现redis内存数据的扩容

2.redis分片本身没有高可用效果的 如果宕机将直接影响用户使用.

redis哨兵的特点:

1.Redis哨兵可以实现Redis节点的高可用性,但是哨兵本身没有实现高可用性机制(最好不要引入第三方).

2.Redis哨兵有主从结构 实现了内存数据的备份.但是没有实现内存数据的扩容效果.

升级

需要Redis内容扩容的同时需要Redis高可用性所以应该使用Redis集群.

1.2关于Redis集群搭建问题说明

1.关闭所有Redis服务器

sh stop.sh

2.删除多余文件

image

3.重启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

1.3Redis入门案例

@Test
    public void testCluster(){
        Set<HostAndPort> nodes = new HashSet<>();
        nodes.add(new HostAndPort("192.168.126.129", 7000));
        nodes.add(new HostAndPort("192.168.126.129", 7001));
        nodes.add(new HostAndPort("192.168.126.129", 7002));
        nodes.add(new HostAndPort("192.168.126.129", 7003));
        nodes.add(new HostAndPort("192.168.126.129", 7004));
        nodes.add(new HostAndPort("192.168.126.129", 7005));
        JedisCluster jedisCluster = new JedisCluster(nodes);
        jedisCluster.set("cluster", "集群的测试!!!!");
        System.out.println(jedisCluster.get("cluster"));

    }

1.4关于选举机制-脑裂现象

说明:当集群进行选举时,如果连续3次都出现了平票的结果则可能出现脑裂现象.

问题:出现脑裂现象的概率是多少????1/8

数学建模:

抛硬币连续3次出现平票的概率是多少?1/8

第一次: 正正 正反 反正 反反 1/2

第二次: 正正 正反 反正 反反 1/2

第三次: 正正 正反 反正 反反 1/2

预防:增加主节点的数量可以有效降低脑裂现象的发生.

1.5关于集群的面试题

问题1:Redis集群中最多存储16384个数据????

错的,分区只负责数据的划分,数据的存储由内存决定.

crc16(key1)%16384=1000

crc16(key2)%16384=1000

问题2:Redis集群中最多有多少台主机??16384

一个主机占用一个槽道

1.6SpringBoot整合Redis集群

1.6.1编辑pro配置文件

# 配置redis单台服务器
redis.host=192.168.126.129
redis.port=6379

# 配置redis分片机制
redis.nodes=192.168.126.129:6379,192.168.126.129:6380,192.168.126.129:6381

# 配置哨兵节点
redis.sentinel=192.168.126.129:26379

# 配置redis集群
redis.clusters=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.6.2编辑RedisConfig配置类

@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class JedisConfig {

    @Value("${redis.clusters}")
    private String clusters;

    @Bean
    public JedisCluster jedisCluster(){
        Set<HostAndPort> nodes = new HashSet<>();
        String[] nodesArray = clusters.split(",");
        for (String node : nodesArray){
            String host = node.split(":")[0];
            int port = Integer.parseInt(node.split(":")[1]);
            HostAndPort hostAndPort = new HostAndPort(host,port);
            nodes.add(hostAndPort);
        }
        return new JedisCluster(nodes);
    }
  }

1.6.3编辑CacheAOP

image

1.7关于京淘项目后台说明

知识点概括

1.框架加强阶段

1.1SpringBoot各个配置文件的说明pom.xml配置 常用注解 springboot启动执行流程.

1.2关于SpringBoot常见用法 属性赋值@Value 开发环境优化,配置文件引入,整合Mybatis,整合Mybatis-Plus,整合WEB资源(JSP)

1.3京淘后台搭建

1.3.1分布式思想 按照模块/按照层级划分

1.3.2聚合工程创建的思路,父级项目,统一管理jar包,工具API项目,业务功能系统

1.4UI工具前端与后端进行数据交互时,如果想要展现特定的格式结构,则必须按照要求返回VO对象.

1.5JSON结构形式1.Object类型2.Array类型3.复杂类型(可以进行无限层级的嵌套).

1.6后台商品/商品分类的CURD操作.

1.7引入富文本编辑器/实现文件上传业务.

1.8反向代理/正向代理

1.9NGINX实现图片的回显,NGINX安装/命令/进程项说明/域名的代理/负载均衡机制/相关属性说明/

1.10window tomcat服务器的部署

2Linux学习

2.1什么是VM虚拟机.网络配置说明 桥接/NAT模式

2.2介绍Linux的发展,介绍Linux的命令 安装Linux JDK tomcatLinux部署.Linux安装MySQL数据

2.3Linux安装nginx服务器:整个项目linux部署.

3.项目真实部署

3.1实现数据的读写分离/负载均衡/数据库高可用mycat

3.2Redis命令/redis单台操作/redis分片/redis哨兵/redis集群

3.3AOP相关知识

image

2.京淘项目前台搭建

2.1京淘项目架构图

image

2.2京淘前台项目搭建

2.2.1创建项目

image

2.2.2添加继承/依赖/插件

说明:编辑jt-web的pom.xml文件其中打包的方式注意改成war 其次添加继承/依赖/插件

<?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>
    <packaging>war</packaging>

    <parent>
        <artifactId>jt</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <!--2.添加依赖信息-->
    <dependencies>
        <!--依赖实质依赖的是jar包文件-->
        <dependency>
            <groupId>com.jt</groupId>
            <artifactId>jt-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <!--3.添加插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

将课前资料中的文件导入.如图所示

image

2.2.3关于web项目数据源报错的说明

SringBoot程序启动时需要加载数据库但是没有数据源的配置信息.导致报错.

image

如何解决:添加排除数据源启动

image

2.2.4修改SpringBoot启动项

image

2.2.5启动效果测试

image

2.2.6编辑Nginx配置文件

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

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

编辑hosts文件

image

2.2.7关于谷歌浏览器https禁用问题

谷歌浏览器输入:chrome://net-internals/#hsts

修改完成后重启浏览器即可

image

2.3关于伪静态的说明

2.3.1业务说明

问题1:京东的商品有很多,如果都采用静态页面的形式为用户展现数据,如果有100万的商品,那么就需要100万个xxx.html页面,请问京东是如何做到的.

实现规则:

应该动态获取商品的ID号.之后查询数据库,然后调整指定的页面,将数据进行填充即可.

问题2:为什么京东采用.html结尾的请求展现商品那?

采用.html结尾的页面更加容易被搜索引擎收录,提高网站曝光率.

image

2.3.2搜索引擎工作原理

工作原理核心:倒排索引机制,根据关键字检索文章位置.

image

2.3.3伪静态思想

伪静态是相对真实静态来讲的,通常我们为了增强搜索引擎的友好面,都将文章内容生成静态页面,但是有的朋友为了实时的显示一些信息。或者还想运用动态脚本解决一些问题。不能用静态的方式来展示网站内容。但是这就损失了对搜索引擎的友好面。怎么样在两者之间找个中间方法呢,这就产生了伪静态技术。伪静态技术是指展示出来的是以html一类的静态页面形式,但其实是用ASP一类的动态脚本来处理的。

总结:以.html结尾的静态页面,增强搜索引擎的友好性.

2.3.4伪静态实现

说明:如果需要实现伪静态,则需要拦截.html结尾的请求即可,否则程序认为你访问的是具体的静态资源如图所示.

image

配置类介绍

@Configuration                          //web.xml配置文件
public class MvcConfigurer implements WebMvcConfigurer{
    
    //开启匹配后缀型配置
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {

        //开启后缀类型的匹配.  xxxx.html
        configurer.setUseSuffixPatternMatch(true);
    }
}
查看原文

赞 0 收藏 0 评论 0

BolunWu 发布了文章 · 10月24日

京淘Day16

1.实现用户模块的跳转

1.1需求说明

说明:当用户点击登陆/注册按钮时,需要跳转到指定的页面中.

image

url地址1:http://www.jt.com/user/regist...

url地址2:http://www.jt.com/user/login....

1.2编辑UseController

package com.jt.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@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
     * 要求:实现通用页面跳转
     * restFul方式: 1.动态获取url中的参数,之后实现通用的跳转.
     */
    @RequestMapping("/{moduleName}")
    public String module(@PathVariable String moduleName){

        return moduleName;
    }

}

1.3页面效果展现

image

2.创建JT-SSO项目创建

2.1创建项目

image

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-sso</artifactId>
    <!--默认的打包方式就是jar  不写也没有关系-->
    <packaging>jar</packaging>

    <parent>
        <artifactId>jt</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <!--2.添加依赖信息-->
    <dependencies>
        <!--依赖实质依赖的是jar包文件-->
        <dependency>
            <groupId>com.jt</groupId>
            <artifactId>jt-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <!--3.添加插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.3编辑User的POJO对象

@TableName("tb_user")
@Data
@Accessors(chain = true)
public class User extends BasePojo{

    @TableId(type = IdType.AUTO)//设定主键自增
    private Long id;            //用户ID号
    private String username;    //用户名
    private String password;    //密码 需要md5加密
    private String phone;       //电话号码
    private String email;       //暂时使用电话代替邮箱

}

2.4测试JT-SSO项目

用户通过sso.jt.com/findUserAll获取User表中的信息json返回.

代码结构如下

image

2.4.1编辑UserController

package com.jt.controller;

import com.jt.pojo.User;
import com.jt.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 完成测试按钮
     * 1.url地址 :findUserAll
     * 2.参数信息: null
     * 3.返回值结果: List<User>
     *
     */
    @RequestMapping("/findUserAll")
    public List<User> findUserAll(){

        return userService.findUserAll();
    }
}

2.4.2编辑UserService

package com.jt.service;

import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements UserService{

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findUserAll() {

        return userMapper.selectList(null);
    }
}

2.4.3修改nginx配置

image

3.跨域的实现(重要)

3.1跨域访问测试

3.1.1同域测试

分析:

1.浏览器地址: http://manage.jt.com/test.html

2.ajax请求地址: http://manage.jt.com/test.json

结论:

当浏览器地址与ajax请求的地址(协议://域名:端口)相同时可以实现正常的业务调用.

<script type="text/javascript" data-original="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
    <!--引入类库之后,执行js代码-->
<script type="text/javascript">
    <!--让整个页面加载完成之后执行js-->
    $(function(){
        $.get("http://manage.jt.com/test.json",function(data){
            alert(data.name);
        })
    })
</script>

image

3.1.2跨域测试

分析:

1.浏览器地址: http://www.jt.com/test.html

2.ajax请求地址: http://manage.jt.com/test.json

结论:

如果请求地址(协议://域名:端口)不相同则导致请求调用失败

3.2浏览器-同源策略说明

说明:浏览器规定,发起ajax时如果请求协议/端口号如果3者有一个与当前的浏览器的地址不相同时,则违反了同源策略的规定,则浏览器不予解析返回值.

跨域问题:违反同源策略得的规定就是跨域请求.

3.3跨域1-JSONP

3.3.1JSONP跨域原理

1.利用javascript中的src属性实现跨域请求.

2.自定义回调函数function callback(xxxx).

3.将返回值结果进行特殊的格式封装callback(json)

4.由于利用src属性进行调用 所以只能支持get请求类型

封装返回值

hello({"id":"1","name":"tom"})

页面JS编辑

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试JSON跨域问题</title>    
    <script type="text/javascript">
        /*JS是解释执行的语言  */
        /*定义回调函数  */
        function hello(data){
            alert(data.name);
        }
    </script>
    <!--该json一直保存到浏览器中等待调用,但是没有函数名称无法调用  -->
    <script type="text/javascript" data-original="http://manage.jt.com/test.json"></script>
    <script type="text/javascript" data-original="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
</head>
<body>
    <h1>JS跨域问题</h1>
</body>
</html>

image

3.3.2JSONP

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的

3.3.3JSONP优化

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSONP测试</title>
<script type="text/javascript" data-original="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
    $(function(){
        alert("测试访问开始!!!!!")
        $.ajax({
            url:"http://manage.jt.com/web/testJSONP",
            type:"get",                //jsonp只能支持get请求
            dataType:"jsonp",       //dataType表示返回值类型
            jsonp: "callback",    //指定参数名称
            jsonpCallback: "hello",  //指定回调函数名称
            success:function (data){   //data经过jQuery封装返回就是json串
                console.log(data);
            }
        });    
    })
</script>
</head>
<body>
    <h1>JSON跨域请求测试</h1>
</body>
</html>

3.3.4编辑后端Controller

package com.jt.web.controller;

import com.jt.pojo.ItemDesc;
import com.jt.util.ObjectMapperUtil;
import jdk.nashorn.internal.runtime.regexp.JoniRegExp;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class JSONPController {

    /**
     * 实现JSONP跨域请求
     * url地址: http://manage.jt.com/web/testJSONP?callback=xxxxxx
     * 参数:    暂时没有可以不接
     * 返回值:  callback(JSON);
     */
     @RequestMapping("/web/testJSONP")
     public String testJSONP(String callback){
         ItemDesc itemDesc = new ItemDesc();
         itemDesc.setItemId(1000L).setItemDesc("JSONP测试!!!");
         String json = ObjectMapperUtil.toJSON(itemDesc);
         return callback+"("+json+")";
     }

}

3.3.5后端控制台输出

image

3.3.6JSONObject说明

 @RequestMapping("/web/testJSONP")
    public JSONPObject testJSONP(String callback){
        ItemDesc itemDesc = new ItemDesc();
        itemDesc.setItemId(1000L).setItemDesc("JSONP测试!!!");
        return new JSONPObject(callback, itemDesc);
    }

3.4cors跨域方式

3.4.1cors调用原理

image

3.4.2实现cors调用

package com.jt.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration  //标识我是一个配置类
public class CorsConfig implements WebMvcConfigurer {

    //在后端 配置cors允许访问的策略
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedMethods("GET","POST") //定义允许跨域的请求类型
                .allowedOrigins("*")           //任意网址都可以访问
                .allowCredentials(true) //是否允许携带cookie
                .maxAge(1800);                 //设定请求长链接超时时间.
    }
}

3.4.3cors调用响应头解析

image

3.4.4cors跨域测试

image

json数据格式

image

3.5关于跨域总结

1.jsonp

jsonp本质是利用JavaScript中的src属性的get请求实现跨域 返回值必须经过特殊格式封装.

2.cors

添加在响应头中的信息.指定哪些服务器允许访问.

实现用户数据校验

4.1业务需求

当用户注册时,如果输入用户名,则应向jt-sso单点登录系统发起请求,校验用户数据是否存在.如果存在则提示用户.image

4.2业务接口文档说明

image

4.3前端JS分析

1.url分析

image

2.检索JS代码

image

3.JS分析

 $.ajax({
                url : "http://sso.jt.com/user/check/"+escape(pin)+"/1?r=" + Math.random(),
                dataType : "jsonp",
                success : function(data) {
                    checkpin = data.data?"1":"0";
                    if(data.status == 200){
                         if (!data.data) {
                            validateSettings.succeed.run(option);
                            namestate = true;
                         }else {
                            validateSettings.error.run(option, "该用户名已占用!");
                            namestate = false;
                         }
                    }else{
                          validateSettings.error.run(option, "服务器正忙,请稍后!");
                          namestate = false;
                    }

                }
            });

4.4编辑JT-SSO UserController

  /**
     * 业务说明: jt-web服务器获取jt-sso数据 JSONP跨域请求
     * url地址: http://sso.jt.com/user/check/{param}/{type}
     * 参数:    param: 需要校验的数据   type:校验的类型
     * 返回值:  SysResult对象
     * 真实的返回值: callback(SysResult的JSON)
     */
    @RequestMapping("/check/{param}/{type}")
    public JSONPObject checkUser(@PathVariable String param,
                                 @PathVariable Integer type,
                                 String callback){
        //true 表示数据存在     false 表示数据可以使用
        boolean flag = userService.checkUser(param,type);
        SysResult.success(flag);
        return new JSONPObject(callback, SysResult.success(flag));
    }

4.5 编辑JT-SSO UserService

 /**
     * 判断依据:  根据用户名查询 如果结果>0 用户已存在.
     * @param param
     * @param type
     * @return
     */
    @Override
    public boolean checkUser(String param, Integer type) {
        //1.需要将type类型转化为 具体字段信息  1=username  2=phone  3=email
        String column = columnMap.get(type);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(column, param);
        Integer count = userMapper.selectCount(queryWrapper);
        return  count > 0 ? true :false;
    }

4.6页面效果展现

image

查看原文

赞 0 收藏 0 评论 0

BolunWu 发布了文章 · 10月24日

京淘Day18

1.Dubbo

1.1Dubbo介绍

Apache Dubbo是一款高性能,轻量级的开源java RPC框架,它提供三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现.

image

1.2Dubbo的特点

image

2Dubbo入门案例

2.1定义公共接口项目

说明:接口项目一般定义公共部分,并且被第三方依赖.

image

2.2服务提供者介绍

2.2.1提供者代码结构

image

2.2.2编辑实现类

package com.jt.dubbo.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.dubbo.config.annotation.Service;
import com.jt.dubbo.mapper.UserMapper;
import com.jt.dubbo.pojo.User;
@Service(timeout=3000)    //3秒超时 内部实现了rpc
//@org.springframework.stereotype.Service//将对象交给spring容器管理
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    @Override
    public List<User> findAll() {
        
        System.out.println("我是第一个服务的提供者");
        return userMapper.selectList(null);
    }
    
    @Override
    public void saveUser(User user) {
        
        userMapper.insert(user);
    }
}

2.2.3编辑提供者配置文件

server:
  port: 9000   #定义端口

spring:
  datasource:
    #引入druid数据源
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: root

#关于Dubbo配置   
dubbo:
  scan:
    basePackages: com.jt    #指定dubbo的包路径 扫描dubbo注解
  application:              #应用名称
    name: provider-user     #一个接口对应一个服务名称   一个接口可以有多个实现
  registry:  #注册中心 用户获取数据从机中获取 主机只负责监控整个集群 实现数据同步
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
  protocol:  #指定协议
    name: dubbo  #使用dubbo协议(tcp-ip)  web-controller直接调用sso-Service
    port: 20880  #每一个服务都有自己特定的端口 不能重复.

      
mybatis-plus:
  type-aliases-package: com.jt.dubbo.pojo       #配置别名包路径
  mapper-locations: classpath:/mybatis/mappers/*.xml  #添加mapper映射文件
  configuration:
    map-underscore-to-camel-case: true                #开启驼峰映射规则

2.2服务消费者介绍

package com.jt.dubbo.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.dubbo.pojo.User;
import com.jt.dubbo.service.UserService;

@RestController
public class UserController {
    
    //利用dubbo的方式为接口创建代理对象 利用rpc调用
    @Reference
    private UserService userService; 
    
    /**
     * Dubbo框架调用特点:远程RPC调用就像调用自己本地服务一样简单
     * @return
     */
    @RequestMapping("/findAll")
    public List<User> findAll(){
        
        //远程调用时传递的对象数据必须序列化.
        return userService.findAll();
    }
    
    @RequestMapping("/saveUser/{name}/{age}/{sex}")
    public String saveUser(User user) {
        
        userService.saveUser(user);
        return "用户入库成功!!!";
    }
}

2.3.2编辑YML配置文件

server:
  port: 9001
dubbo:
  scan:
    basePackages: com.jt
  application:
    name: consumer-user   #定义消费者名称
  registry:               #注册中心地址
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183

2.3.3入门案例测试

image

2.4关于Dubbo框架知识点

2.4.1问题1:如果其中一个服务器宕机,用户访问是否受限?

由于ZK的帮助,使得程序可以永远访问正确的服务器,并且当服务重启时,dubbo有服务的自动发现功能,消费者不需要重启既可以访问新的服务.

2.4.2问题2:如果ZK集群短时间宕机,用户访问是否受限?

用户访问不受影响,由于消费者在本地储存服务列表信息,当访问故障机,自动将标识信息改为down属性.

2.5Dubbo负载均衡策略

2.5.1负载均衡种类

1.客户端负载均衡

Dobbo/SpringCloud等微服务框架

image

2.服务端负载均衡

说明:客户端发起请求后,必须由统一的服务器进行负载均衡,所有的压力都在服务器之中.

NGINX

image

2.5.2Dubbo负载均衡方式

@RestController
public class UserController {
    
    //利用dubbo的方式为接口创建代理对象 利用rpc调用
    //@Reference(loadbalance = "random")            //默认策略  负载均衡随机策略
    //@Reference(loadbalance = "roundrobin")        //轮询方式
    //@Reference(loadbalance = "consistenthash")    //一致性hash  消费者绑定服务器提供者
    @Reference(loadbalance = "leastactive")            //挑选当前负载小的服务器进行访问
    private UserService userService; 

}

京淘项目Dubbo改造

3.1改造JT-SSO

3.1.1添加jar包文件

        <!--引入dubbo配置 -->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>0.2.0</version>
        </dependency>

3.1.2创建DubboUserService接口

image

3.1.3创建提供者实现类

image

3.1.3编辑提供者YML配置文件

server:
  port: 8093
  servlet:
    context-path: /
spring:
  datasource:
    #引入druid数据源
    #type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: root

  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp
#mybatis-plush配置
mybatis-plus:
  type-aliases-package: com.jt.pojo
  mapper-locations: classpath:/mybatis/mappers/*.xml
  configuration:
    map-underscore-to-camel-case: true

logging:
  level: 
    com.jt.mapper: debug

#关于Dubbo配置
dubbo:
  scan:
    basePackages: com.jt    #指定dubbo的包路径 扫描dubbo注解
  application:              #应用名称
    name: provider-user     #一个接口对应一个服务名称   一个接口可以有多个实现
  registry:  #注册中心 用户获取数据从机中获取 主机只负责监控整个集群 实现数据同步
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
  protocol:  #指定协议
    name: dubbo  #使用dubbo协议(tcp-ip)  web-controller直接调用sso-Service
    port: 20880  #每一个服务都有自己特定的端口 不能重复.

3.1.4启动服务提供者

测试Dubbo服务类是否正常启动

image

3.2改造服务消费者JT-WEB

3.2.1注入Service接口

image

3.2.2编辑消费者配置文件

server:
  port: 8092    
spring:     #定义springmvc视图解析器
  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp

dubbo:
  scan:
    basePackages: com.jt
  application:
    name: consumer-web   #定义消费者名称
  registry:               #注册中心地址
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183

  

3.2.3启动效果测试

image

4.用户模块实现

4.1用户注册

4.1.1URL分析

说明:根据url地址说明请求为同域请求

image

参数信息

image

4.1.2页面JS分析

image

4.1.3编辑UserController

 /**
     * 需求: 实现用户信息注册
     * 1.url请求地址:  http://www.jt.com/user/doRegister
     * 2.请求参数:     {password:_password,username:_username,phone:_phone},
     * 3.返回值结果:   SysResult对象
     */
    @RequestMapping("/doRegister")
    @ResponseBody   //将数据转化为JSON
    public SysResult saveUser(User user){
        //消费者给予dubbo协议将user对象进行远程网络数据传输.
        userService.saveUser(user);
        return SysResult.success();
    }

4.1.4编辑UserService

/**
     * 注意事项:
     *  1.暂时使用电话号码代替邮箱
     *  2.密码进行md5加密.
     *  3.入库操作注意事务控制
     * @param user
     */
    @Override
    public void saveUser(User user) {
        String md5Pass =
                DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
        user.setEmail(user.getPhone())
            .setPassword(md5Pass);
        userMapper.insert(user);
    }

4.1.5页面效果展示

image

4.2关于ZK数据储存结构

说明:在ZK的数据储存采用树形结构的方式保存.

命令:[root@localhost bin]# sh zkCli.sh

查询命令:ls/...

image

4.3用户单点登录原理介绍

4.3.1传统方式登录存在的问题

说明:如果采用Session的方式实现用户的登陆操作,由于nginx的负载均衡的策略,用户可以访问不同的服务器,但是Session不能共享,所以导致用户频繁登陆,用户体验不好.

image

4.3.2SSO

单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录。当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现是不需要管理员对用户的登录状态或其他信息进行修改的,这意味着在多个应用系统中,用户只需一次登录就可以访问所有相互信任的应用系统。这种方式减少了由登录产生的时间消耗,辅助了用户管理,是目前比较流行的 .

4.3.3京淘项目单点登录设计

image

实现步骤:

1.当用户输入用户名和密码点击登录时,将请求发送给JT-WEB消费者服务器.

2.JT-WEB服务器将用户信息传递给JT-SSO单点登录系统完成系统校验.

3.如果登陆成功,则动态生成秘钥信息,将user数据转换为json,保存到redis中,注意超时时间的设定.

4.JT-SSO将登陆的凭证传给JT-WEB服务器.

5.JT-WEB服务器将用户秘钥ticket信息保存到用户cookie中注意超时时间设定.

6.如果登陆不成功则直接返回错误信息即可.

4.4用户单点登陆实现.

4.4.1页面url分析

image

4.4.2页面参数分析

image

4.4.3页面JS分析

image

4.4.4编辑UserController

 /**
     * 完成用户登录操作
     * 1.url地址: http://www.jt.com/user/doLogin?r=0.9309436837648131
     * 2.参数:    {username:_username,password:_password},
     * 3.返回值结果:  SysResult对象
     *
     * 4.Cookie:
     *   4.1 setPath("/")  path表示如果需要获取cookie中的数据,则url地址所在路径设定.
     *       url:http://www.jt.com/person/findAll
     *       cookie.setPath("/");   一般都是/
     *       cookie.setPath("/person");
     *   4.2 setDomain("xxxxx")  设定cookie共享的域名地址.
     */
    @RequestMapping("/doLogin")
    @ResponseBody
    public SysResult doLogin(User user, HttpServletResponse response){
        String ticket = userService.doLogin(user);
        if(StringUtils.isEmpty(ticket)){
            //说明用户名或者密码错误
            return SysResult.fail();
        }else{
            //1.创建Cookie
            Cookie cookie = new Cookie("JT_TICKET",ticket);
            cookie.setMaxAge(7*24*60*60);   //设定cookie存活有效期
            cookie.setPath("/");            //设定cookie有效范围
            cookie.setDomain("jt.com");     //设定cookie共享的域名 是实现单点登录必备要素
            response.addCookie(cookie);
            return SysResult.success();     //表示用户登录成功!!
        }
    }

4.4.5编辑UserService

/**
     * 1.获取用户信息校验数据库中是否有记录
     * 2.有  开始执行单点登录流程
     * 3.没有 直接返回null即可
     * @param user
     * @return
     */
    @Override
    public String doLogin(User user) {  //username/password
        //1.将明文加密
        String md5Pass =
                DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
        user.setPassword(md5Pass);
        QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
        //根据对象中不为null的属性当做where条件.
        User userDB = userMapper.selectOne(queryWrapper);
        if(userDB == null){
            //用户名或密码错误
            return null;
        }else{ //用户名和密码正确  实现单点登录操作
            String ticket = UUID.randomUUID().toString();
            //如果将数据保存到第三方 一般需要脱敏处理
            userDB.setPassword("123456你信不??");
            String userJSON = ObjectMapperUtil.toJSON(userDB);
            jedisCluster.setex(ticket, 7*24*60*60, userJSON);
            return ticket;
        }
    }

4.4.5页面效果展现

image

查看原文

赞 0 收藏 0 评论 0

BolunWu 发布了文章 · 10月23日

京淘Day20

购物车删除操作

1.1页面分析

image

1.2编辑CartController

  /**
     * 购物车删除操作
     * url地址: http://www.jt.com/cart/delete/562379.html
     * 参数:    获取itemId
     * 返回值:  重定向到购物车的展现页面
     */
    @RequestMapping("/delete/{itemId}")
    public String deleteCarts(@PathVariable Long itemId){

        Long userId = 7L;
        cartService.deleteCarts(userId,itemId);
        return "redirect:/cart/show.html";
    }

1.3编辑CartService

 @Override
    public void deleteCarts(Long userId, Long itemId) {
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("item_id", itemId);
        cartMapper.delete(queryWrapper);
    }

2.京淘权限实现

2.1业务需求

当用户进行敏感操作时,必须要求用户先登录之后才能访问后端服务器.例如京东商城.

使用技术:

1.AOP 2.拦截器:拦截用户的请求

image

2.2定义京淘拦截器

2.2.1SpringMVC调用原理图

image

2.2.2SpringMVC拦截器工作原理

image

2.2.3配置拦截器

@Component  //spring容器管理对象
public class UserInterceptor implements HandlerInterceptor {

    @Autowired
    private JedisCluster jedisCluster;

    //Spring版本升级 4 必须实现所有的方法  spring 5 只需要重写指定的方法即可.

    /**
     * 需求:   拦截/cart开头的所有的请求进行拦截.,并且校验用户是否登录.....
     * 拦截器选择: preHandler
     * 如何判断用户是否登录:  1.检查cookie信息   2.检查Redis中是否有记录.
     *          true : 请求应该放行
     *          false: 请求应该拦截 则配合重定向的语法实现页面跳转到登录页面 使得程序流转起来

     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1.判断用户是否登录  检查cookie是否有值
        String ticket = CookieUtil.getCookieValue(request,"JT_TICKET");
        //2.校验ticket
        if(!StringUtils.isEmpty(ticket)){
            //3.判断redis中是否有值.
            if(jedisCluster.exists(ticket)){
                //4.动态获取json信息
                String userJSON = jedisCluster.get(ticket);
                User user = ObjectMapperUtil.toObj(userJSON,User.class);
                request.setAttribute("JT_USER",user);
                return true;
            }
        }
        response.sendRedirect("/user/login.html");
        return false;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //销毁数据
        request.removeAttribute("JT_USER");
    }
}

2.2.4获取动态UserId

image

2.3ThreadLocal介绍

2.3.1ThreadLocal作用

名称:本地线程变量

作用:可以在同一线程内,实现数据共享.

image

2.3.2ThreadLocal入门案例

     private ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
    public void a(){
        int a = 100;
        threadLocal.set(a);
        b();
    }

    public void b(){
        int a = threadLocal.get();
        int b  = 100*a;
    }

2.3.3编辑ThreadLocal工具API

public class UserThreadLocal {

    //static不会影响影响线程  threadLocal创建时跟随线程.
    //private static ThreadLocal<Map<k,v>> threadLocal = new ThreadLocal<>();
    private static ThreadLocal<User> threadLocal = new ThreadLocal<>();

    public static void set(User user){

        threadLocal.set(user);
    }

    public static User get(){

        return threadLocal.get();
    }

    public static void remove(){

        threadLocal.remove();
    }

}

2.3.4重构User拦截器

image

2.3.5动态获取UserId

image

京淘订单模块

3.1订单表设计

image

3.2创建订单项目

3.2.1创建项目

image

3.2.2添加继承依赖

  <!--2.添加依赖信息-->
    <dependencies>
        <!--依赖实质依赖的是jar包文件-->
        <dependency>
            <groupId>com.jt</groupId>
            <artifactId>jt-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <!--3.添加插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

3.2.3添加POJO

image

删除orderItem的主键标识

image

3.2.4构建jt-order项目

订单项目代码结构如下

image

3.3订单确认页面跳转

3.3.1url分析

image

3.3.2编辑OrderController

package com.jt.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Cart;
import com.jt.service.DubboCartService;
import com.jt.service.DubboOrderService;
import com.jt.thread.UserThreadLocal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/order")
public class OrderController {

    @Reference(timeout = 3000,check = false)
    private DubboOrderService orderService;
    @Reference(timeout = 3000,check = false)
    private DubboCartService cartService;

    /**
     * 订单页面跳转
     * url: http://www.jt.com/order/create.html
     * 页面取值: ${carts}
     */
    @RequestMapping("/create")
    public String create(Model model){

        //1.根据userId查询购物车信息
        Long userId = UserThreadLocal.get().getId();
        List<Cart> cartList = cartService.findCartListByUserId(userId);
        model.addAttribute("carts",cartList);
        return "order-cart";
    }
}

3.3.3编辑OrderService

@Override
    public List<Cart> findCartListByUserId(Long userId) {
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        return cartMapper.selectList(queryWrapper);
    }

3.3.4页面效果展现

image

3.4关于SpringMVC参数提交问题说明

3.4.1简单参数传参问题

1.页面url标识

2.Controller中的方法

public void xxx(String name,int age){
}
public class User{
    private Integer name;
    private String age;
}

3.4.3使用对象的引用为参数赋值

难点:属性的重名提交问题

解决思路:可以采用对象的引用方式为属性赋值

<input  name="name"   value="二郎神"    />
<input  name="age"   value="3000"    />
<input  name="dog.name"   value="哮天犬"    />
<input  name="dog.age"   value="8000"    />

2.Controller中的方法

public void  xxx(User user){
    
    }
    public class Dog{
        private String name;
        private Integer age;    
    }
    public class User{
        private String name;
        private Integer age;    
        private Dog dog;
    }

3.5关于订单提交

3.5.1页面URL说明

image

3.5.2请求参数

image

3.5.3页面JS分析

jQuery.ajax( {
            type : "POST",
            dataType : "json",
            url : "/order/submit",
            data : $("#orderForm").serialize(),
            // data: {"key":"value","key2":"value2".....}
            // data:  id=1&name="xxx"&age=18......
            cache : false,
            success : function(result) {
                if(result.status == 200){
                    location.href = "/order/success.html?id="+result.data;
                }else{
                    $("#submit_message").html("订单提交失败,请稍后重试...").show();
                }
            },
            error : function(error) {
                $("#submit_message").html("亲爱的用户请不要频繁点击, 请稍后重试...").show();
            }
        });

3.5.3编辑OrderController

 /**
     * 订单提交
     * url: http://www.jt.com/order/submit
     * 参数: 整个form表单
     * 返回值: SysResult对象   携带返回值orderId
     * 业务说明:
     *   当订单入库之后,需要返回orderId.让用户查询.
     */
    @RequestMapping("/submit")
    @ResponseBody
    public SysResult saveOrder(Order order){
        Long userId = UserThreadLocal.get().getId();
        order.setUserId(userId);
        String orderId = orderService.saveOrder(order);
        if(StringUtils.isEmpty(orderId))
            return SysResult.fail();
        else
            return SysResult.success(orderId);

    }

3.5.4编辑OrderService

@Service(timeout = 3000)
public class DubboOrderServiceImpl implements DubboOrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderItemMapper orderItemMapper;
    @Autowired
    private OrderShippingMapper orderShippingMapper;

    /**
     * Order{order订单本身/order物流信息/order商品信息}
     * 难点:  操作3张表完成入库操作
     * 主键信息: orderId
     * @param order
     * @return
     */
    @Override
    public String saveOrder(Order order) {
        //1.拼接OrderId
        String orderId =
                "" + order.getUserId() + System.currentTimeMillis();
        //2.完成订单入库
        order.setOrderId(orderId).setStatus(1);
        orderMapper.insert(order);

        //3.完成订单物流入库
        OrderShipping orderShipping = order.getOrderShipping();
        orderShipping.setOrderId(orderId);
        orderShippingMapper.insert(orderShipping);

        //4.完成订单商品入库
        List<OrderItem> orderItems = order.getOrderItems();
        //批量入库  sql: insert into xxx(xxx,xx,xx)values (xx,xx,xx),(xx,xx,xx)....
        for (OrderItem orderItem : orderItems){
            orderItem.setOrderId(orderId);
            orderItemMapper.insert(orderItem);
        }
        System.out.println("订单入库成功!!!!");
        return orderId;
    }
}

3.6订单成功跳转

3.6.1页面url分析

image

3.6.2编辑OrderController

 /**
     * 实现商品查询
     * 1.url地址: http://www.jt.com/order/success.html?id=71603356409924
     * 2.参数说明: id 订单编号
     * 3.返回值类型: success.html
     * 4.页面取值方式: ${order.orderId}
     */
    @RequestMapping("/success")
    public String findOrderById(String id,Model model){
        Order order = orderService.findOrderById(id);
        model.addAttribute("order",order);
        return "success";
    }

3.6.2编辑OrderService

 @Override
    public Order findOrderById(String id) {
        //1.查询订单信息
        Order order  = orderMapper.selectById(id);
        //2.查询订单物流信息
        OrderShipping orderShipping = orderShippingMapper.selectById(id);
        //3.查询订单商品
        QueryWrapper<OrderItem> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id",id);
        List<OrderItem> lists =orderItemMapper.selectList(queryWrapper);
        return order.setOrderItems(lists).setOrderShipping(orderShipping);
    }

3.6.3页面效果展现

image

4.项目结构图

image

查看原文

赞 0 收藏 0 评论 0

BolunWu 发布了文章 · 10月21日

京淘Day19

1.用户模块的实现

1.1用户信息回显

1.1.1页面URL分析

image

1.1.2检查页面JS

image

1.1.3编辑JT-SSO的Controller

/**
     * 业务实现:
     *  1.用户通过cookie信息查询用户数据.    通过ticket获取redis中的业务数据.
     *  2.url请求: http://sso.jt.com/user/query/+ _ticket
     *  3.参数:    参数在url中. 利用restFul获取
     *  4.返回值要求: SysResult对象(userJSON)
     */
    @RequestMapping("/query/{ticket}")
    public JSONPObject findUserByTicket(@PathVariable String ticket,
                                        HttpServletResponse response,
                                        String callback){

        String userJSON = jedisCluster.get(ticket);
        //1.lru算法清空数据   2.有可能cookie信息有误
        if(StringUtils.isEmpty(userJSON)){
            //2.应该删除cookie信息.
            Cookie cookie = new Cookie("JT_TICKET", "");
            cookie.setMaxAge(0);
            cookie.setDomain("jt.com");
            cookie.setPath("/");
            response.addCookie(cookie);
            return new JSONPObject(callback,SysResult.fail());
        }
        return new JSONPObject(callback,SysResult.success(userJSON));
    }

1.2编辑Cookie工具API

package com.jt.util;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CookieUtil {

    //1.新增cookie
    public static void addCookie(HttpServletResponse response,String cookieName, String cookieValue, int seconds, String domain){
        Cookie cookie = new Cookie(cookieName,cookieValue);
        cookie.setMaxAge(seconds);
        cookie.setDomain(domain);
        cookie.setPath("/");
        response.addCookie(cookie);
    }


    //2.根据name查询value的值
    public static String getCookieValue(HttpServletRequest request,String cookieName){

        Cookie[] cookies = request.getCookies();
        if(cookies !=null && cookies.length >0){
            for (Cookie cookie : cookies){
                if(cookieName.equals(cookie.getName())){
                    return cookie.getValue();
                }
            }
        }
        return null;
    }



    //3.删除cookie
    public static void deleteCookie(HttpServletResponse response,String cookieName,String domain){

        addCookie(response,cookieName,"",0, domain);
    }
}

1.3用户退出操作

1.3.1业务说明

如果用户点击退出操作,首先应该删除Redis中的数据 其次删除Cookie中的数据之后重定向到系统首页.

1.3.2URL分析

image

1.3.3编辑UserController

    /**
     * 实现用户的退出操作.重定向到系统首页
     * url: http://www.jt.com/user/logout.html
     * 业务:
     *      1.删除Redis中的数据  key
     *      2.删除Cookie记录
     */
    @RequestMapping("logout")
    public String logout(HttpServletRequest request,HttpServletResponse response){
        //1.根据JT_TICKET获取指定的ticket
        String ticket = CookieUtil.getCookieValue(request,"JT_TICKET");

        //2.判断ticket是否为null
        if(!StringUtils.isEmpty(ticket)){
            jedisCluster.del(ticket);
            CookieUtil.deleteCookie(response,"JT_TICKET","jt.com");
        }

        return "redirect:/";
    }

2.实现商品详情展现

2.1业务说明

说明:当用户点击商品时,需要跳转到商品的展现页面中,页面名称item.jsp

image

2.1重构JT-MANAGE

2.2.1创建接口

说明:在jt-common中创建接口

image

2.2.2编辑Dubbo实现类

package com.jt.service;


import com.alibaba.dubbo.config.annotation.Service;
import com.jt.mapper.ItemDescMapper;
import com.jt.mapper.ItemMapper;
import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import org.springframework.beans.factory.annotation.Autowired;

@Service(timeout = 3000)
public class DubboItemServiceImpl implements DubboItemService{

    @Autowired
    private ItemMapper itemMapper;
    @Autowired
    private ItemDescMapper itemDescMapper;


    @Override
    public Item findItemById(Long itemId) {

        return itemMapper.selectById(itemId);
    }

    @Override
    public ItemDesc findItemDescById(Long itemId) {

        return itemDescMapper.selectById(itemId);
    }
}

2.2.3编辑YML文件配置

server:
  port: 8091
  servlet:
    context-path: /
spring:
  datasource:
    #引入druid数据源
    #type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: root

  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp
#mybatis-plush配置
mybatis-plus:
  type-aliases-package: com.jt.pojo
  mapper-locations: classpath:/mybatis/mappers/*.xml
  configuration:
    map-underscore-to-camel-case: true

logging:
  level: 
    com.jt.mapper: debug

#关于Dubbo配置
dubbo:
  scan:
    basePackages: com.jt    #指定dubbo的包路径 扫描dubbo注解
  application:              #应用名称
    name: provider-manage     #一个接口对应一个服务名称   一个接口可以有多个实现
  registry:  #注册中心 用户获取数据从机中获取 主机只负责监控整个集群 实现数据同步
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
  protocol:  #指定协议
    name: dubbo  #使用dubbo协议(tcp-ip)  web-controller直接调用sso-Service
    port: 20881  #每一个服务都有自己特定的端口 不能重复.

2.2.4编辑ItemController

package com.jt.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Item;
import com.jt.pojo.ItemDesc;
import com.jt.service.DubboItemService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/items")
public class ItemController {

    @Reference(timeout = 3000)
    private DubboItemService itemService;

    /**
     * 实现商品详情页面跳转
     * url: http://www.jt.com/items/562379.html
     * 参数: 562379 itemId
     * 返回值:  item.jsp页面
     * 页面取值说明:
     *      ${item.title }   item对象
     *      ${itemDesc.itemDesc }  itemDesc对象
     *
     * 思路:
     *      1.重构jt-manage项目
     *      2.创建中立接口DubboItemService
     *      3.实现业务调用获取item/itemDesc对象
     */
    @RequestMapping("/{itemId}")
    public String findItemById(@PathVariable Long itemId, Model model){

        Item item = itemService.findItemById(itemId);
        ItemDesc itemDesc = itemService.findItemDescById(itemId);
        //将数据保存到request域中
        model.addAttribute("item",item);
        model.addAttribute("itemDesc",itemDesc);
        return "item";
    }
}

2.2.5页面效果展现

image

3.购物车模块实现

3.1创建服务提供者

3.3.1创建项目JT-CART

image

3.1.2添加继承/依赖/插件

 <!--2.添加依赖信息-->
    <dependencies>
        <!--依赖实质依赖的是jar包文件-->
        <dependency>
            <groupId>com.jt</groupId>
            <artifactId>jt-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <!--3.添加插件-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

3.1.3编辑POJO对象

@TableName("tb_cart")
@Data
@Accessors(chain = true)
public class Cart extends BasePojo{  //使用包装类型

    @TableId(type = IdType.AUTO)
    private Long id;
    private Long uesrId;        //用户ID号
    private Long itemId;        //商品ID号
    private String itemTitle;   //商品标题
    private String itemImage;   //图片
    private Long itemPrice;     //商品价格
    private Integer num;        //商品数量

}

3.1.4编辑CartService接口

image

3.1.5jt-cart代码结构

image

3.2购物车列表页面实现

3.2.1页面URL分析

说明:当用户点击购物车按钮时,需要跳转到购物车展现页面cart.jsp

页面取值:${cartList}

要求:只查询userId=7的购物车列表信息,之后进行页面展现.

image

3.2.2编辑CartController

package com.jt.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Cart;
import com.jt.service.DubboCartService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/cart")
public class CartController {

    @Reference(timeout = 3000,check = false)
    private DubboCartService cartService;

    /**
     * 业务需求: 根据userId查询购物车数据
     * url地址: http://www.jt.com/cart/show.html
     * 请求参数: 动态获取userId
     * 返回值结果:  cart.jsp页面
     * 页面取值方式: ${cartList}
     */
    @RequestMapping("/show")
    public String findCartListByUserId(Model model){
        Long userId = 7L;
        List<Cart> cartList = cartService.findCartListByUserId(userId);
        model.addAttribute("cartList",cartList);
        return "cart";
    }
}

3.2.3编辑CartService

package com.jt.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.mapper.CartMapper;
import com.jt.pojo.Cart;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

@Service
public class DubboCartServiceImpl implements DubboCartService{

    @Autowired
    private CartMapper cartMapper;


    @Override
    public List<Cart> findCartListByUserId(Long userId) {
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        return cartMapper.selectList(queryWrapper);
    }
}

3.2.4页面效果展示

image

3.3购物车数量的修改

3.3.1业务说明

image

3.3.2页面JS分析

image
image

3.3.3编辑CartController

  /**
     * 业务: 实现购物车数量的更新
     * url: http://www.jt.com/cart/update/num/562379/12
     * 参数: itemId/num
     * 返回值: void
     */
    @RequestMapping("/update/num/{itemId}/{num}")
    @ResponseBody  //1.返回值转化为json 2.ajax结束标识
    public void updateCartNum(Cart cart){ //key名称必须与属性的名称一致.

        Long userId = 7L;
        cart.setUserId(userId);
        cartService.updateCartNum(cart);
    }

3.3.4编辑CartService

 @Override
    public void updateCartNum(Cart cart) {

        //cartMapper.updateCartNum(cart);
        //1.准备修改的数据  根据对象中不为null的元素当做set条件
        Cart cartTemp = new Cart();
        cartTemp.setNum(cart.getNum());

        //2.根据对象中不为null的元素当做where条件
        UpdateWrapper<Cart> updateWrapper =
                        new UpdateWrapper<>(cart.setNum(null));
        /*updateWrapper.eq("user_id", cart.getUserId())
                     .eq("item_id", cart.getItemId());*/
        cartMapper.update(cartTemp,updateWrapper);

    }

3.3.5编辑CartMapper

public interface CartMapper extends BaseMapper<Cart> {
    @Update("update tb_cart set num = #{num},updated=now() where user_id=#{userId} and item_id=#{itemId}")
    void updateCartNum(Cart cart);
}

3.4购物车新增

3.4.1购物车新增业务

说明:当用户点击购物车按钮时实现购物车入库操作.如果用户重复加购则应该修改购物车商数量.加购成功后,应该重定向到购物车列表页面.

3.4.2页面分析

image

3.4.3页面表单提交

<form id="cartForm" method="post">
                                    <input class="text" id="buy-num" name="num" value="1" onkeyup="setAmount.modify('#buy-num');"/>
                                    <input type="hidden" class="text"  name="itemTitle" value="${item.title }"/>
                                    <input type="hidden" class="text" name="itemImage" value="${item.images[0]}"/>
                                    <input type="hidden" class="text" name="itemPrice" value="${item.price}"/>
                                </form>

3.4.4页面JS解析

<a class="btn-append " id="InitCartUrl" onclick="addCart();" clstag="shangpin|keycount|product|initcarturl">加入购物车<b></b></a>
//利用post传值
        function addCart(){
            var url = "http://www.jt.com/cart/add/${item.id}.html";
            document.forms[0].action = url;        //js设置提交链接
            document.forms[0].submit();            //js表单提交
        }

3.4.5编辑CartController

 /**
     * 完成购物车新增
     * url: http://www.jt.com/cart/add/562379.html
     * 参数: form表单提交  对象接收
     * 返回值: 重定向到购物车列表页面中
     */
    @RequestMapping("/add/{itemId}")
    public String saveCart(Cart cart){

        Long userId = 7L;
        cart.setUserId(userId);
        cartService.saveCart(cart);
        return "redirect:/cart/show.html";
    }

3.4.6编辑CartService

/**
     *  如果重复加购则更新数量
     * 1.查询是否已经有改数据 user_id/item_id
     */
    @Override
    public void saveCart(Cart cart) {
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", cart.getUserId())
                    .eq("item_id", cart.getItemId());
        Cart cartDB = cartMapper.selectOne(queryWrapper);
        if(cartDB == null){
            //用户第一次加购
            cartMapper.insert(cart);
        }else {
            //用户需要修改数量
            int num = cart.getNum() + cartDB.getNum();
            cart.setNum(num);
            cartMapper.updateCartNum(cart);
        }
    }

3.4.6页面效果

image

查看原文

赞 0 收藏 0 评论 0

BolunWu 关注了用户 · 10月19日

欧阳思海 @sihai_5ae5ba9170388

欢迎关注微信公众号【好好学java】,这里分享我历时三个月总结的【Java 面试 + Java 后端技术学习指南】,这是本人这几年及春招的总结,已经拿到了腾讯等大厂offer,整理成了一本电子书,拿去不谢。现在免费分享大家,在我的公众号【好好学java】,回复【Java面试】即可获取。

关注 2516

BolunWu 发布了文章 · 10月19日

京淘Day17

JSONP全局异常处理机制

1.1问题说明

当后端服务器执行出错时,会执行全局异常的处理.但是JSONP的请求的调用要求 返回值类型 callback(JSON)结构,所以需要重构全局异常处理的返回值结构类型.

image

1.2编辑全局异常处理机制

package com.jt.aop;

import com.fasterxml.jackson.databind.util.JSONPObject;
import com.jt.vo.SysResult;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.sql.SQLException;

//@ControllerAdvice  //拦截controller层
//@ResponseBody
@RestControllerAdvice   //定义全局异常的处理类   AOP=异常通知
public class SystemAOP {

    /**
     *  定义全局异常的方法  当遇到了什么异常时,程序开始执行   参数一般class类型
     *  如果一旦发生异常,则应该输出异常的信息,之后返回错误数据即可.
     *
     *  解决跨域全局异常处理的规则: 京淘项目的跨域都是使用JSONP.   http://xxxx?callback=xxxxx
     *  如果请求中携带了callback参数 则认为是JSONP跨域请求.
     *  难点: 如何获取callback参数呢??/
     */
    @ExceptionHandler({RuntimeException.class})
    public Object systemAop(Exception e, HttpServletRequest request){
        e.printStackTrace();
        String callback  = request.getParameter("callback");
        if(StringUtils.isEmpty(callback)){
            //常规方法调用方式
            return SysResult.fail();
        }else{
            //证明是jsonp跨域请求
            return new JSONPObject(callback, SysResult.fail());
        }
    }
}

2.HttpClient请求

2.1业务需求

业务说明:当做某些操作时,可能会对数据进行业务加工,之后由服务器和服务器之间形成通讯.

image
image

2.2HttpClient介绍

Http协议可能是现在Interent上使用最多 最重要的协议了.越来也多的java应用程序需要直接通过Http协议来访问网络资源.虽然在JDK的java net包中已经提供了访问HTTP协议的基本功能,但是对于大部分应用程序来说,JDK库本身提供的功能还不够丰富和灵活.HttpClient是Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。HttpClient 已经应用在很多的项目中,比如 Apache Jakarta 上很著名的另外两个开源项目 Cactus 和 HTMLUnit 都使用了 HttpClient。现在HttpClient最新版本为 HttpClient 4.5 .6(2015-09-11).

总结:在java代理内部可以使用httpClient发起http请求访问服务器获取资源.(工具API)

2.3HttpClient入门案例

2.3.1引入jar包

  <!--添加httpClient jar包 -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>

2.3.2编辑测试API

package com.jt;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;

import java.io.IOException;

public class HttpClientTest {

    /**
     * 要求:在java代码内部,获取百度的页面.
     * 实现步骤:
     *  1.确定目标地址: https://www.baidu.com/
     *  2.创建httpClient客户端对象
     *  3.创建请求类型
     *  4.发起http请求.并且获取响应的结果.之后判断状态码是否为200 如果等于200则请求正确
     *  5.如果请求正确则动态获取响应值信息.之后进行数据的再次加工....
     *  */
    @Test
    public void testGet() throws IOException {
        String url = "https://www.jd.com/";
        HttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        HttpResponse httpResponse = httpClient.execute(httpGet);
        if(httpResponse.getStatusLine().getStatusCode() == 200) {
            //表示用户请求正确
            //获取返回值数据
            HttpEntity httpEntity = httpResponse.getEntity();
            String result = EntityUtils.toString(httpEntity, "UTF-8");
            System.out.println(result);
        }
    }
}

2.4HttpClient加强案例

2.4.1案例要求

用户通过网址 http://www.jt.com/getItems 要求采用httpClient方式,获取jt-manage中的商品信息 之后json串的形式展现.jt-web服务器访问jt-manage时的网址http://manage.jt.com/getItems.

2.4.2编辑前台HttpClientController

package com.jt.controller;

import com.jt.pojo.Item;
import com.jt.service.HttpClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class HttpClientController {

    @Autowired
    private HttpClientService httpClientService;
    /**
     * 获取后端manage中的商品数据信息
     */
    @RequestMapping("/getItems")
    public List<Item> getItems(){

        return httpClientService.getItems();
    }
}

2.4.2编辑前台HttpClientService

package com.jt.service;

import com.jt.pojo.Item;
import com.jt.util.ObjectMapperUtil;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Service
public class HttpClientServiceImpl implements HttpClientService{

    @Override
    public List<Item> getItems() {
        List<Item> itemList = new ArrayList<>();
        //1.定义远程访问网址
        String url = "http://manage.jt.com/getItems";
        HttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        try {
           HttpResponse httpResponse = httpClient.execute(httpGet);
           if(httpResponse.getStatusLine().getStatusCode() == 200){
               String result =
                       EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
               //result是jt-manage为jt-web返回的List<Item>的JSON串
               if(!StringUtils.isEmpty(result)){
                   itemList = ObjectMapperUtil.toObj(result, itemList.getClass());
               }
           }
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        return itemList;
    }
}

2.4.3编辑后台HttpClientController

package com.jt.web.controller;

import com.jt.pojo.Item;
import com.jt.service.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class HttpClientController {

    @Autowired
    private ItemService itemService;

    /**
     * url请求地址: http://manage.jt.com/getItems
     */
    @RequestMapping("/getItems")
    public List<Item> getItems(){

        return itemService.getItems();
    }

 }

2.4.4编辑后台HttpClientService

@Override
    public List<Item> getItems() {

        return itemMapper.selectList(null);
    }

2.4.5页面展现效果

image

3.SOA思想(微服务代理编辑的标准)

面向服务的架构(SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分,并通过这些服务之间定义良好的接口和协议联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种各样的系统中的服务可以以一种统一和通用的方式进行交互。

image

4.RPC思想介绍

RPC是远程过程调用(Remote Procedure Call)的缩写形式。

总结:

1.当完成业务时自己没有办法直接完成时,需要通过第三方帮助才能完成的业务.

2.使用RPC时"感觉"上就是在调用自己的方法完成业务.

5.微服务思想

核心:1.分布式思想(拆)2.自动化(HA,自动化)

5.1传统项目问题

1.如果采用nginx方式实现负载均衡,当服务数量改变时,都必须手动的修改nginx.conf配置文件.不够智能.

2.所有的请求都会通过nginx服务器作为中转.如果nginx服务器一旦宕,则直接影响整个系统.nginx最好只做简单的反向代理即可.

传统方式不够智能

image

5.2微服务的调用方式介绍

image

调用步骤

1.将服务信息写入到注册中心(1.服务名称 2.服务IP地址 3.端口)

2.注册中心接收到服务器信息会动态维护服务列表数据.

3.消费者启动时会链接注册中心,目的是获取服务列表数据.

4.注册中心会将服务列表数据同步给消费者,并且保存到消费者本地,以后方便调用.

5.当消费者开始业务调用时,会根据已知的服务信息进行负载均衡操作,访问服务提供者.

6.当服务提供者宕机时,由于注册中心有心跳检测机制,所以会动态维护服务列表.

7.当注册中心的服务列表变化时,则会全网进行广播,通知所有消费者更新本地服务列表.

5.3Zookeeper注册中心介绍

ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

ZooKeeper包含一个简单的原语集,提供Java和C的接口。

ZooKeeper代码版本中,提供了分布式独享锁、选举、队列的接口,代码在$zookeeper_homesrcrecipes。其中分布锁和队列有Java和C两个版本,选举只有Java版本。

概括:ZK主要的任务是服务的调度,提供一致性功能.

5.4关于集群的知识介绍

5.4.1最小的集群单位几台

公式:存活节点的数量 > N/2集群可以创建

1台: 1-1<1/2 不能创建

2台: 2-1=2/2 不能创建

3台: 3-1>3/2 可以创建

4台: 4-1>4/2 可以创建

结论:搭建集群的最小单位3台.

5.4.2为什么集群一般都是奇数

原则:myid最大值优先 myid值越大的越容易当选主机 超半数同意即当选主机.

题目:问1,2,3,4,5,6,7依次启动 问谁能当选主机 谁永远当选不了主机?

当投票进行到4时,4得票过半 当选主机.

因为1,2,3的得票永远不可能超过半数 所以1,2,3永远当选不了主机.

查看原文

赞 0 收藏 0 评论 0

BolunWu 发布了文章 · 10月18日

跨域的实现

跨域访问测试

同域测试

分析

1.浏览器地址:http://manage.jt.com/test.html

2.浏览器地址: http://manage.jt.com/test.json

结论

当浏览器地址与ajax请求的地址(协议://域名:端口)相同时可以实现正常的义务调用.

跨域测试

分析

1.浏览器地址: http://www.jt.com/test.html

2.2.ajax请求地址: http://manage.jt.com/test.json

结论

如果请求地址(协议://域名:端口)不相同则导致请求调用失败

浏览器-同源策略说明

说明:浏览器规定发起ajax请求时如果请求协议/域名/端口号如果三种中有一个与当前浏览器的地址不相同时,则违反了同源策略的规定,则浏览器不予以解析返回值.

跨域问题:违反同源策略的规定就是跨域请求.

跨域-JSONP

JSONP垮域原理

1.利用javascrpit中的src属性实现跨域请求.

2.自定义回调函数 function callback(xxx).

3.将返回值结果进行特殊格式封装 callback(json).

4.由于利用src属性进行调用 所以只支持get请求类型

封装返回值

hello({"id":"1","name":"tom"})

页面js编辑

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSONP测试</title>
<script type="text/javascript" data-original="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
    $(function(){
        alert("测试访问开始!!!!!")
        $.ajax({
            url:"http://manage.jt.com/web/testJSONP",
            type:"get",                //jsonp只能支持get请求
            dataType:"jsonp",       //dataType表示返回值类型
            jsonp: "callback",    //指定参数名称
            jsonpCallback: "hello",  //指定回调函数名称
            success:function (data){   //data经过jQuery封装返回就是json串
                console.log(data);
            }
        });    
    })
</script>
</head>
<body>
    <h1>JSON跨域请求测试</h1>
</body>
</html>

JSONP

JSONP(JSON with Padding)是JSON的一种使用模式,可用于解决主流浏览器的跨域数据访问问题.由于同源策略,一般来说位于 server1.example.com的网页无法与不是 server1.example.com的服务器进行沟通.

JSONP优化.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSONP测试</title>
<script type="text/javascript" data-original="http://manage.jt.com/js/jquery-easyui-1.4.1/jquery.min.js"></script>
<script type="text/javascript">
    $(function(){
        alert("测试访问开始!!!!!")
        $.ajax({
            url:"http://manage.jt.com/web/testJSONP",
            type:"get",                //jsonp只能支持get请求
            dataType:"jsonp",       //dataType表示返回值类型
            jsonp: "callback",    //指定参数名称
            jsonpCallback: "hello",  //指定回调函数名称
            success:function (data){   //data经过jQuery封装返回就是json串
                console.log(data);
            }
        });    
    })
</script>
</head>
<body>
    <h1>JSON跨域请求测试</h1>
</body>
</html>

编辑后端Controller

package com.jt.web.controller;

import com.jt.pojo.ItemDesc;
import com.jt.util.ObjectMapperUtil;
import jdk.nashorn.internal.runtime.regexp.JoniRegExp;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class JSONPController {

    /**
     * 实现JSONP跨域请求
     * url地址: http://manage.jt.com/web/testJSONP?callback=xxxxxx
     * 参数:    暂时没有可以不接
     * 返回值:  callback(JSON);
     */
     @RequestMapping("/web/testJSONP")
     public String testJSONP(String callback){
         ItemDesc itemDesc = new ItemDesc();
         itemDesc.setItemId(1000L).setItemDesc("JSONP测试!!!");
         String json = ObjectMapperUtil.toJSON(itemDesc);
         return callback+"("+json+")";
     }

}

控制台输出

image

JSONPObject说明

 @RequestMapping("/web/testJSONP")
    public JSONPObject testJSONP(String callback){
        ItemDesc itemDesc = new ItemDesc();
        itemDesc.setItemId(1000L).setItemDesc("JSONP测试!!!");
        return new JSONPObject(callback, itemDesc);
    }

cors跨域方式

cors调用原理

image

实现cors调用

package com.jt.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration  //标识我是一个配置类
public class CorsConfig implements WebMvcConfigurer {

    //在后端 配置cors允许访问的策略
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedMethods("GET","POST") //定义允许跨域的请求类型
                .allowedOrigins("*")           //任意网址都可以访问
                .allowCredentials(true) //是否允许携带cookie
                .maxAge(1800);                 //设定请求长链接超时时间.
    }
}

cors调用响应头解析

image

cors跨域测试

image

JSON数据格式

image

关于跨域的总结

1.jsonp

jsonp本质利用javaScript中的src属性的get请求实现的跨域

返回值必须经过特殊格式封装

2.cors

添加在响应头中的信息,指定在那些服务器中访问

查看原文

赞 0 收藏 0 评论 0

BolunWu 发布了文章 · 10月16日

关于伪静态的说明

业务说明

问题1.京东的商品很多,如果都采用静态页面的形式为用户展现数据效果,如果有100万的商品,那么就需要100万个xxx.html页面.问京东是如何做到的???

实现规则:

应该动态获取商品的ID号,之后查询数据库,然后调整指定页面,将数据进行填充即可.

问题2.为什么京东采用.html结尾的请求展现商品呢???

采用.html结尾的页面.更加容易被搜索引擎收录,提高网站的曝光度.

image

搜索引擎工作原理

工作原理核心:倒排索引机制.根据关键字检索文章位置.

image

伪静态思想

伪静态是相对于真实静态来讲的,通常我们为了增强搜索引擎的又好面(曝光度),都将文章内容生成静态页面,但是有的朋友为了实时的显示一些信息.或者还想运用动态脚本解决一些问题.不能用静态的方式来展现网站内容.但是这就损失了对搜索引擎的友好面.怎么样在两者中间找个好的方法那.这就产生了伪静态技术.伪静态技术是展式出来的是以html一类的静态页面形式,但其实是ASP一类的动态脚本来处理的.

总结:以.html结尾的动态页面,增强搜索引擎的友好性.

伪静态实现

说明如果需要实现伪静态,则需要拦截.html结尾的请求即可.否则程序认为你访问的是具体的静态资源如图所示:

image

配置类介绍:

@Configuration                          //web.xml配置文件
public class MvcConfigurer implements WebMvcConfigurer{
    
    //开启匹配后缀型配置
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {

        //开启后缀类型的匹配.  xxxx.html
        configurer.setUseSuffixPatternMatch(true);
    }
}
查看原文

赞 0 收藏 0 评论 0

BolunWu 发布了文章 · 10月15日

关于Redis 缓存面试题

关于Redis 缓存

=============

问题描述:

由于海量的用户请求 如果这时redis服务器出现问题 则可能导致整个系统崩溃.

运行速度:

1.tomcat服务器150-250之间 JVM调优 1000/秒

2.NGINX 3-5万秒

3.REDIS 读11.2万/秒 写8.6万/秒 平均10万/秒

缓存穿透

问题描述:

由于用户高并发环境下访问 数据库中不存在的数据时 ,容易导致缓存穿透.

如何解决:

设定IP限流的操作 nginx中 或者微软服务机制API网关实现.

缓存击穿

问题描述:

由于用户高并发环境下, 由于某个数据之前存在于内存中,但是由于特殊原因(数据超时/数据意外删除)导致redis缓存失效. 而使大量的用户的请求直接访问数据库.

如何解决:

1.设定超时时间时,不要设定一样的时间.

2.设定多级缓存.

image

缓存雪崩

说明:由于高并发条件下有大量数据失效,导致redis的命中率太低,而使得用户直接访问数据库(服务器)导致崩溃,称之为缓存雪崩.

解决方案:

1.不要设定相同的超时时间 随机数

2.设定多级缓存

3.提高redis的命中率 调整redis内存优化策略采用LRU等算法.

image

查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 0 次点赞
  • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 8月25日
个人主页被 206 人浏览