课堂笔记-2009-zg6

亮子 2023-04-19 06:14:05 11332 0 0 0

学习要求

  • 自律
  • 自信
  • 自学

话术要求

https://www.shenmazong.com/album/1553219581379571712/1

前四节话术都要背

  • 秒杀话术
  • hashmap的扩容机制
  • 分布式锁(实现方式、实现原理、项目中的实现)

技术点

  • nginx 的反向代理以及负载均衡
  • sentelnal 熔断和降级
  • skywalking 链路追踪
  • docker环境搭建、docker镜像制作、Jenkins 自动化部署
  • 腾讯直播
  • 移动支付
  • 订单超时
  • 秒杀

项目创建

  • 用户中心的pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.shenma2009</groupId>
    <artifactId>server-shop-user</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>server-shop-user</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
        <spring-cloud-alibaba.version>2.2.2.RELEASE</spring-cloud-alibaba.version>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.shenma2009.ServerShopUserApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
  • 配置文件 application.properties

spring.application.name=server-shop-user # 应用服务 WEB 访问端口 server.port=9000 # Nacos认证信息 spring.cloud.nacos.discovery.username=nacos spring.cloud.nacos.discovery.password=1912@a # Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口 spring.cloud.nacos.discovery.server-addr=8.142.83.78:8848 # 注册到 nacos 的指定 namespace,默认为 public spring.cloud.nacos.discovery.namespace=public spring.cloud.nacos.discovery.group=zhouhaijun ## mybatis plus #下面这些内容是为了让MyBatis映射 #指定Mybatis的Mapper文件 mybatis.mapper-locations=classpath:mappers/*xml #指定Mybatis的实体目录 mybatis.type-aliases-package=com.shenma2009.pojo # 数据库驱动: spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # 数据源名称 spring.datasource.name=defaultDataSource # 数据库连接地址 spring.datasource.url=jdbc:mysql://localhost:3306/db_shop_2009a?autoReconnect= true&useUnicode= true&characterEncoding=utf8&serverTimezone=Asia/Shanghai # 数据库用户名&密码: spring.datasource.username=root spring.datasource.password=123456 # SQL调试日志 logging.level.com.shenma2009.mapper=debug # 逻辑删除配置 mybatis-plus.global-config.db-config.logic-delete-field=deleted mybatis-plus.global-config.db-config.logic-not-delete-value=0 mybatis-plus.global-config.db-config.logic-delete-value=1

用户中的增删改查

详细了解RBAC(Role-Based Access Control)

https://shenmazong.com/blog/1591262099727699968

图片alt

  • 分页拦截器
package com.shenma2009.filter;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author 军哥
 * @version 1.0
 * @description: MybatisPlusConfig
 * @date 2023/4/19 16:45
 */

@Configuration
@MapperScan("com.shenma2009.mapper*")
public class MybatisPlusConfig {

    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}

https://www.shenmazong.com/blog/1529682926714634240

常用工具类

swagger3

        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>
package com.shenma2009.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @author 军哥
 * @version 1.0
 * @description: Knife4j 配置类
 * @date 2022/5/26 9:56
 */

@Configuration
@EnableSwagger2
public class Knife4jConfiguration {
    @Bean(value = "defaultApi2")
    public Docket defaultApi2() {
        String groupName="3.X版本";
        Docket docket=new Docket(DocumentationType.OAS_30)
                .apiInfo(new ApiInfoBuilder()
                        .title("这是knife4j API ")
                        .description("# 这里记录服务端所有的接口的入参,出参等等信息")
                        .termsOfServiceUrl("https://www.shenmazong.com")
                        .contact(new Contact("亮子说编程","https://www.shenmazong.com","3350996729@qq.com"))
                        .version("3.0")
                        .build())
                //分组名称
                .groupName(groupName)
                .select()
                //这里指定Controller扫描包路径
                .apis(RequestHandlerSelectors.basePackage("com.shenma2009.controller"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }
}

token工具类

        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.11.4</version>
        </dependency>
package com.shenma2009.utils;

import io.jsonwebtoken.*;

import java.util.ArrayList;
import java.util.Date;

/**
 * @author 军哥
 * @version 1.0
 * @description: JWT生成token工具类
 * @date 2022/6/22 15:06
 */

public class TokenUtils {

    public static int SUCCESS = 0;
    public static int ERROR_SIGN = 1;
    public static int ERROR_EXPIRE = 2;
    public static int ERROR = 3;

    private String key = "123456";
    private Integer expireTime = 60;
    private Claims claims = null;
    JwtBuilder builder = null;

    public TokenUtils() {
        builder = Jwts.builder();
    }

    public static TokenUtils token() {
        return new TokenUtils();
    }

    public TokenUtils setKey(String key) {
        this.key = key;
        return this;
    }

    public TokenUtils setExpire(Integer seconds) {
        this.expireTime = seconds;

        // 设置签发日期
        builder.setIssuedAt(new Date());
        // 设置过期时间
        long now = System.currentTimeMillis();
        long exp = now+1000*expireTime;
        builder.setExpiration( new Date( exp ) );

        return this;
    }

    public TokenUtils setClaim(String key, String value) {
        builder.claim( key, value );
        return this;
    }

    /**
     * @description 生成最终token
     * @author 军哥
     * @date 2022/6/22 15:44
     * @version 1.0
     */
    public String makeToken() {
        // 设置签名 使用HS256算法,并设置SecretKey(字符串)
        builder.signWith(SignatureAlgorithm.HS256,key);

        // 生成token
        String token = builder.compact();

        return token;
    }


    /**
     * @description 存放多个Key-Value数据
     * @author 军哥
     * @date 2022/6/22 15:47
     * @version 1.0
     */
    public TokenUtils putKeyValues(String... keyValues) {
        if(keyValues.length > 0) {
            // 添加数据
            ArrayList<String> stringPair = new ArrayList<>();
            for(String kv:keyValues) {
                // 添加键值对
                stringPair.add(kv);
                //
                if(stringPair.size()>=2) {
                    builder.claim( stringPair.get(0),stringPair.get(1) );
                    stringPair.clear();
                    continue;
                }
            }
        }

        return this;
    }

    /**
     * @description 添加键值对数据,然后生成token
     * @author 军哥
     * @date 2022/6/22 15:45
     * @version 1.0
     */
    public String createToken(String... keyValues) {

        // 存放数据
        if(keyValues.length > 0) {
            // 添加数据
            ArrayList<String> stringPair = new ArrayList<>();
            for(String kv:keyValues) {
                // 添加键值对
                stringPair.add(kv);
                //
                if(stringPair.size()>=2) {
                    builder.claim( stringPair.get(0),stringPair.get(1) );
                    stringPair.clear();
                    continue;
                }
            }
        }

        //
        // 设置签名 使用HS256算法,并设置SecretKey(字符串)
        builder.signWith(SignatureAlgorithm.HS256,key);

        // 生成token
        String token = builder.compact();

        return token;
    }

    public int parseToken(String token) {
        try {
            claims = Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(token)
                    .getBody();
            return TokenUtils.SUCCESS;
        }
        catch (ExpiredJwtException e) {
            System.out.println("token expired");
            claims  = e.getClaims();
            return TokenUtils.ERROR_EXPIRE;
        } catch (SignatureException e) {
            System.out.println("token signature error");
            return TokenUtils.ERROR_SIGN;
        } catch (Exception e) {
            System.out.println("token error");
            return TokenUtils.ERROR;
        }
    }

    public String getClaim(String key) {
        if(claims == null) {
            return null;
        }

        String value = (String)claims.get(key);

        return value;
    }

    /**
     * @description 测试工具类
     * @author 军哥
     * @date 2022/6/22 15:49
     * @version 1.0
     */
    public static void main(String[] args) {
        String token = TokenUtils.token()
                // 设置加密密码
                .setKey("123456")
                // 设置过期时间
                .setExpire(60 * 30)
                // 添加数据
                .setClaim("id", "" + 666)
                .setClaim("userName", "zhaoyun")
                .putKeyValues("role", "admin", "permissions", "select,delete,insert")
                // 生成token
                .makeToken();
        System.out.println("token="+token);
    }
}

redis可视化

package com.shenma2009.config;

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author 军哥
 * @version 1.0
 * @description: 配置自定义redisTemplate
 * @date 2022/2/9 11:23
 */

@Configuration
@EnableCaching
public class RedisConfig {
    /**
     * 配置自定义redisTemplate
     * @return
     */
    @Bean
    RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {

        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        // 设置值(value)的序列化采用Jackson2JsonRedisSerializer。
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        // 设置键(key)的序列化采用StringRedisSerializer。
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

git 仓库初始化

git init
git remote add origin https://gitee.com/ywbingchuan/server-shop-2009.git
git push -u origin "master"