Docker 安装

CentOS 版本官方安装文档:https://docs.docker.com/engine/install/centos/

  • 卸载旧版

    1. $ sudo yum remove docker \
    2. docker-client \
    3. docker-client-latest \
    4. docker-common \
    5. docker-latest \
    6. docker-latest-logrotate \
    7. docker-logrotate \
    8. docker-engine
  • 设置 yum 库 ```shell $ sudo yum install -y yum-utils

官方源,比较慢

$ sudo yum-config-manager \ —add-repo \ https://download.docker.com/linux/centos/docker-ce.repo

建议使用阿里源

$ sudo yum-config-manager \ —add-repo \ http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

  1. - 安装
  2. ```shell
  3. $ sudo yum install docker-ce docker-ce-cli containerd.io
  • 启动

    1. $ sudo systemctl start docker
  • 设置开机自启

    1. $ systemctl enable docker
  • 测试

    1. $ docker images
    2. REPOSITORY TAG IMAGE ID CREATED SIZE
    3. $ docker -v
    4. Docker version 19.03.12, build 48a66213fe
  • 配置镜像阿里云加速

开发环境搭建 - 图1
开发环境搭建 - 图2

  1. sudo mkdir -p /etc/docker
  2. sudo tee /etc/docker/daemon.json <<-'EOF'
  3. {
  4. "registry-mirrors": ["https://bcozo2zh.mirror.aliyuncs.com"]
  5. }
  6. EOF
  7. sudo systemctl daemon-reload
  8. sudo systemctl restart docker

Docker 安装 Mysql

  • 拉取 Mysql 镜像

    1. # 注意只能用 5.7 版本,其他版本的操作不一样
    2. docker pull mysql:5.7
  • 运行容器,\ 代表换行

    1. docker run -p 3306:3306 --name mysql \
    2. -v /www/docker/mysql/log:/var/log/mysql \
    3. -v /www/docker/mysql/data:/var/lib/mysql \
    4. -v /www/docker/mysql/conf:/etc/mysql \
    5. -e MYSQL_ROOT_PASSWORD=123 \
    6. -d mysql
  • 配置字符编码

    1. [mysqld]
    2. default-character-set = utf8
    3. # character_set_server = utf8

    Docker 安装 Redis

  • 拉取 Redis 镜像

    1. docker pull redis
  • 运行容器

    1. docker run -p 8883:6379 --name redis \
    2. -v /www/docker/redis/data:/data \
    3. -v /www/docker/redis/conf/redis.conf:/etc/redis/redis.conf \
    4. -d redis redis-server /etc/redis/redis.conf
  • 使用redis 镜像执行 redis-cli 命令连接

    1. docker exec -it redis redis-cli
  • 配置持久化

在 redis/conf/redis.conf 中加入以下内容,然后重启容器

  1. appendonly yes

想知道 redis 的更多配置可以参照官方文档

配置 Maven 与 Java

  1. $ mvn -v
  2. Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
  3. Maven home: /Library/apache-maven-3.6.3
  4. Java version: 1.8.0_221, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre
  5. Default locale: zh_CN, platform encoding: UTF-8
  6. OS name: "mac os x", version: "10.14.4", arch: "x86_64", family: "mac"
  7. $ java -v
  8. Unrecognized option: -v
  9. Error: Could not create the Java Virtual Machine.
  10. Error: A fatal exception has occurred. Program will exit.
  11. caideMacBook-Pro:NewServer cai$

配置 IDEA 插件

lombok 插件:自动生成 getter 和 setter 方法
mybatisx 插件:从 xxxMapper.xml 快速跳转到对应接口

配置 git

  1. $ git config --global user.name "Cai_Programmer"
  2. $ git config --global user.email "1050440470@qq.com"
  3. $ ssh-keygen -t rsa -C "1050440470@qq.com"
  4. Generating public/private rsa key pair.
  5. Enter file in which to save the key (/root/.ssh/id_rsa):
  6. Enter passphrase (empty for no passphrase):
  7. Enter same passphrase again:
  8. Your identification has been saved in /root/.ssh/id_rsa.
  9. Your public key has been saved in /root/.ssh/id_rsa.pub.
  10. The key fingerprint is:
  11. SHA256:k/bvYXYUbvV3tuilP4LTMKdO3WnWQY76fS6luzm5pxY 1050440470@qq.com
  12. The key's randomart image is:
  13. +---[RSA 2048]----+
  14. | |
  15. | |
  16. | ...|
  17. | . .+o.|
  18. | S .+o=|
  19. | . o oo+E.O|
  20. | .o@o.%.|
  21. | .Bo=%oo|
  22. | .o+=O%+|
  23. +----[SHA256]-----+
  24. [root@iZwz91sneajs2ji49vo4wxZ docker]# cat /root/.ssh/id_rsa.pub
  25. ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCnP4Y9fKMNQF7pm7OqfL/hh5wYcmKqQl2op2QpLkKxvYdRmxyziDC43fXBQfbovErGSFgGrvyJkMH+sZfwntv7GbmOI2xLMJVYDGlpKBZEFRqvNTV8HrXrwTBS0w7+COm3jndwZcmzwccWwb0E81wVBTMFmRZ/BkS+BXtN92KqJnJnzI0goCnjG2PAyILSAqWx84MmOX5zAGRgy2TDHgUZ2Fjod3QmiWrR2nHzk/6lrAMXWjjtSEhIa+Odvi9IM/qSp7NKmW7gEnEH3AmOe+AZBJvq/vzIDXrrDSJw+Puc00FZyOzyhzfmO2gi3yAkIKwJ4aj11w8BkL6wHNGnv7bP 1050440470@qq.com

登陆码云 -> 进入设置 -> 安全设置 -> SSH 公钥 -> 把生成的密钥配置到码云
使用 ssh -T git@gitee.com 测试配置是否成功

  1. $ ssh -T git@gitee.com
  2. The authenticity of host 'gitee.com (212.64.62.174)' can't be established.
  3. ECDSA key fingerprint is SHA256:FQGC9*****bVr17bmjey0Wc.
  4. ECDSA key fingerprint is MD5:27:e5:d******d:1f:c1:47:a3:54:b1.
  5. Are you sure you want to continue connecting (yes/no)? yes
  6. Warning: Permanently added 'gitee.com,212.64.62.174' (ECDSA) to the list of known hosts.
  7. Hi 蔡俊伟! You've successfully authenticated, but GITEE.COM does not provide shell access.

配置完成后推送代码到码云就不用输入账号密码了

使用人人开源生成器

https://gitee.com/renrenio/renren-generator

使用 nacos 做注册中心

github 地址:https://github.com/alibaba/nacos 下载地址:https://github.com/alibaba/nacos/releases

  1. # 解压
  2. $ unzip nacos-server-1.0.0.zip
  3. $ cd nacos/bin
  4. # 启动, 默认访问路径为 localhost:8848/nacos
  5. $ startup.sh -m standalone
  • 在项目公共 pom.xml 文件中添加依赖 ```xml com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery

com.alibaba.cloud spring-cloud-alibaba-dependencies 2.1.0.RELEASE pom import

  1. - application.yml 中添加配置
  2. ```sql
  3. spring:
  4. cloud:
  5. nacos:
  6. discovery:
  7. # 注册中心地址
  8. server-addr: 127.0.0.1:8848
  9. application:
  10. # 服务名称
  11. name: gulimall-coupon

先启动 spring boot 服务,访问 localhost:8848/nacos,默认登陆账号和密码都是 nacos,在注册中心可以看到服务注册进来了
image.png

Spring Cloud Feign 远程调用

  • 引入依赖

    1. <dependency>
    2. <groupId>org.springframework.cloud</groupId>
    3. <artifactId>spring-cloud-starter-openfeign</artifactId>
    4. </dependency>
  • 开启 feign 功能

    src/main/java/com/atguigu/gulimall/member/GulimallMemberApplication.java

  1. // 扫描 feign 包
  2. @EnableFeignClients(basePackages = "com.atguigu.gulimall.member.feign")
  3. @EnableDiscoveryClient
  4. @SpringBootApplication
  5. public class GulimallMemberApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run(GulimallMemberApplication.class, args);
  8. }
  9. }

src/main/java/com/atguigu/gulimall/member/feign/CouponFeignService.java

  1. // 服务名称
  2. @FeignClient("gulimall-coupon")
  3. public interface CouponFeignService {
  4. // 请求 url
  5. @RequestMapping("/coupon/coupon/member/list")
  6. public R membercoupons();
  7. }
  • 调用 feign

    src/main/java/com/atguigu/gulimall/member/controller/MemberController.java

  1. @Autowired
  2. private MemberService memberService;
  3. @Autowired
  4. CouponFeignService couponFeignService;
  5. @RequestMapping("/coupons")
  6. public R test(){
  7. MemberEntity memberEntity = new MemberEntity();
  8. memberEntity.setNickname("张三");
  9. R memberCoupons = couponFeignService.memberCoupons();
  10. return R.ok().put("member",memberEntity).put("coupons",memberCoupons.get("coupons"));
  11. }

使用 nacos 做配置中心

使用 nacos 做配置中心,统一管理配置,修改配置不需要打包重新部署项目。

一、基本使用方法

  1. 在公共模块中引入依赖

    gulimall-common/pom.xml

  1. <!-- 配置中心来做配置管理 -->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  5. </dependency>
  1. 创建一个 bootstrap.properties,声明注册中心地址

    gulimall-coupon/src/main/resources/bootstrap.properties

  1. spring.application.name=gulimall-coupon
  2. spring.cloud.nacos.config.server-addr=127.0.0.1:8848
  1. 在配置中心增加数据集(Data Id)

默认命名规则:应用名.properties
image.png

  1. 在控制器中获取配置信息

Spring 会优先使用配置中心的配置
@RefreshScopre:动态获取配置,每次请求都从配置中心获取配置信息
@Value:获取配置
image.png

二、命名空间与分组

1. 命名空间

默认命名空间为 public,命名空间的作用类似文件夹,起到配置分离的作用。
常规使用方法:

  • 生产与开发环境各使用一个命名空间,发布的时候需要修改命名空间 id
  • 每个微服务使用一个命名空间,使用分组隔离生产与开发环境配置,发布的时候需要修改分组名称

    新建一个优惠券系统命名空间

image.png

在该命名空间下新建默认配置文件

image.png

在 bootstrap.properties 中声明命名空间,注意配置的是命名空间 id,不是命名空间名称 gulimall-coupon/src/main/resources/bootstrap.properties

  1. spring.cloud.nacos.config.namespace=59927bf3-18a3-4c42-816a-bcdc528c9a5f

这样就会使用 coupon 命名空间下的 gulimall-coupon.properties 了

2. 配置集

所有配置的集合

3. 配置集 ID

配置的 id,类似文件名
image.png

4. 配置分组

功能类似命名空间,我们可以为每个配置设置一个分组
常规使用方法:新建一套分组为 dev 的配置文件,另加一套分组为 prod 的配置文件,发布的时候只要在 boostrap.properties 中修改分组名称就 ok

新建两个默认配置文件,分组名称分别为 dev 和 prod

image.png

在 bootstrap.properties 中声明分组名称

  1. spring.cloud.nacos.config.group=prod

这样就可以使用指定分组下的配置文件了

三、加载多个配置集

一个微服务的所有配置如果都写在同一个配置文件中会比较难维护,所以一般会把一个微服务的配置拆分到多个配置文件中,使用 nacos 也是可以加载多个配置文件的

新建多个配置文件,datasource.yml、mybatis.yml

image.png

在 bootstrap.properties 中加入配置 gulimall-coupon/src/main/resources/bootstrap.properties

  1. spring.application.name=gulimall-coupon
  2. spring.cloud.nacos.config.server-addr=127.0.0.1:8848
  3. # 配置命名空间
  4. spring.cloud.nacos.config.namespace=59927bf3-18a3-4c42-816a-bcdc528c9a5f
  5. # 配置分组
  6. spring.cloud.nacos.config.group=dev
  7. # 加载多个配置文件
  8. # 配置 data-id
  9. spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
  10. # 配置分组名
  11. spring.cloud.nacos.config.ext-config[0].group=dev
  12. # 配置是否动态刷新配置
  13. spring.cloud.nacos.config.ext-config[0].refresh=true
  14. # 同上,加载第二个配置文件
  15. spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
  16. spring.cloud.nacos.config.ext-config[1].group=dev
  17. spring.cloud.nacos.config.ext-config[1].refresh=true

这样就可以加载多个配置文件了,项目配置中只需要一个 boostrap.properties,其它配置文件都迁移到配置中心

SpringCloud Gateway 网关

官方文档:https://docs.spring.io/spring-cloud-gateway/docs/2.2.7.RELEASE/reference/html

将网关注册到注册中心,在启动类中增加注解 @EnableDiscoveryClient

  1. @EnableDiscoveryClient
  2. @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
  3. public class GulimallGatewayApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(GulimallGatewayApplication.class, args);
  6. }
  7. }

新建 bootstrap.properties,加入注册中心与配置中心地址

  1. spring.application.name=gulimall-gateway
  2. spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
  3. spring.cloud.nacos.config.server-addr=127.0.0.1:8848
  4. server.port=88

新建 application.yml,测试网关
当请求参数存在 url,且值为 baidu 时,会跳转到 https://www.baidu.com
当请求参数存在 url,且值为 qq 时,会跳转到 https://www.qq.com

  1. spring:
  2. cloud:
  3. gateway:
  4. routes:
  5. - id: test_route
  6. uri: https://www.baidu.com
  7. predicates:
  8. - Query=url,baidu
  9. - id: qq_route
  10. uri: https://www.qq.com
  11. predicates:
  12. - Query=url,qq

后台管理网关配置:

gulimall-gateway/src/main/resources/application.yml

  1. spring:
  2. cloud:
  3. gateway:
  4. routes:
  5. - id: product_route
  6. # lb 代表负载均衡,填写微服务名称
  7. uri: lb://gulimall-product
  8. predicates:
  9. # 填写匹配规则,根据路径配置
  10. - Path=/api/product/**
  11. filters:
  12. # 配置路径重写
  13. # 例如:http://localhost:88/api/product/category/list/tree
  14. # 重写后路径:http://server/product/category/list/tree
  15. - RewritePath=/api/(?<segment>.*),/$\{segment}
  16. - id: admin_route
  17. uri: lb://renren-fast
  18. predicates:
  19. - Path=/api/**
  20. filters:
  21. - RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}

在网关中配置允许跨域:

gulimall-gateway/src/main/java/com/atguigu/gulimall/gateway/config/GulimallCorsConfiguration.java

  1. @Configuration
  2. public class GulimallCorsConfiguration {
  3. @Bean
  4. public CorsWebFilter corsWebFilter(){
  5. UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  6. CorsConfiguration corsConfiguration = new CorsConfiguration();
  7. // 配置跨域
  8. corsConfiguration.addAllowedHeader("*");
  9. corsConfiguration.addAllowedMethod("*");
  10. corsConfiguration.addAllowedOrigin("*");
  11. corsConfiguration.setAllowCredentials(true);
  12. // 任意路径
  13. source.registerCorsConfiguration("/**",corsConfiguration);
  14. return new CorsWebFilter(source);
  15. }
  16. }

阿里云OSS对象存储

使用服务端签名直传,文件无需经过应用服务器,直接传给 oss
官方文档:https://help.aliyun.com/document_detail/31926.html?spm=a2c4g.11186623.6.1737.7d5e5a025RchiN
开发环境搭建 - 图11
新建 gulimall-third-party 模块,用于封装第三方服务

  • 引入阿里oss starter

    1. <dependency>
    2. <groupId>com.alibaba.cloud</groupId>
    3. <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
    4. </dependency>
  • 配置注册中心与 oss 账号信息 ```yaml spring: cloud: nacos:

    1. discovery:
    2. server-addr: 127.0.0.1:8848

    alicloud:

    1. access-key: LTAIQkDnEUVliI8Z
    2. secret-key: 67Y2amus4dFKiX5kBWuXP4Jy8xMLvB
    3. oss:
    4. endpoint: oss-accelerate.aliyuncs.com
    5. bucket: iep-server

    application: name: gulimall-third-party

server: port: 30000

  1. - 新建控制器 OssController,用于获取签名
  2. ```java
  3. @RestController
  4. public class OssController {
  5. @Autowired
  6. OSS ossClient;
  7. @Value("${spring.cloud.alicloud.oss.endpoint}")
  8. private String endpoint;
  9. @Value("${spring.cloud.alicloud.oss.bucket}")
  10. private String bucket;
  11. @Value("${spring.cloud.alicloud.access-key}")
  12. private String accessId;
  13. @RequestMapping("/oss/policy")
  14. public R policy() {
  15. String host = "https://" + bucket + "." + endpoint;
  16. // 用户上传文件时指定的前缀。
  17. String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
  18. String dir = format + "/";
  19. long expireTime = 30;
  20. long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
  21. Date expiration = new Date(expireEndTime);
  22. PolicyConditions policyConds = new PolicyConditions();
  23. policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
  24. policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
  25. String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
  26. byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
  27. String encodedPolicy = BinaryUtil.toBase64String(binaryData);
  28. String postSignature = ossClient.calculatePostSignature(postPolicy);
  29. Map<String, String> respMap = new LinkedHashMap<>();
  30. respMap.put("accessid", accessId);
  31. respMap.put("policy", encodedPolicy);
  32. respMap.put("signature", postSignature);
  33. respMap.put("dir", dir);
  34. respMap.put("host", host);
  35. respMap.put("expire", String.valueOf(expireEndTime / 1000));
  36. return R.ok().put("data",respMap);
  37. }
  38. }

JSR-303数据校验

作者:谁在烽烟彼岸 https://www.jianshu.com/p/554533f88370

JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。

JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。

Bean Validation 中内置的 constraint:
开发环境搭建 - 图12

使用方法:

  • 给Bean添加校验注解:javax.validation.constraints,并定义自己的 message 提示

    1. @NotNull(groups = {AddGroup.class})
    2. @Min(value = 0, message = "排序必须大于等于0")
    3. private Integer sort;
  • 控制器接收前端参数时增加 @Validated 注解,代表开启参数校验功能,如果不增加此注解则不会开启校验

    1. @RequestMapping("/save")
    2. public R save(@Validated() @RequestBody BrandEntity brand){
    3. brandService.save(brand);
    4. return R.ok();
    5. }

分组校验功能,用于多场景的复杂校验:

  • 定义分组,只需要声明接口 ```java public interface UpdateGroup {}

public interface AddGroup {}

  1. - 在校验注解中传入 groups 属性,给校验注解标注什么情况需要进行校验
  2. ```java
  3. @NotBlank(message = "品牌名必须提交", groups = {AddGroup.class, UpdateGroup.class})
  • 在控制器中的 Validated 注解中声明分组,默认没有指定分组的校验注解 @NotBlank,在分组校验情况@Validated({AddGroup.class}) 下不生效,只会在 @Validated 生效
    1. @RequestMapping("/save")
    2. public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){
    3. brandService.save(brand);
    4. return R.ok();
    5. }

自定义校验注解:

  • 创建注解

    1. @Documented
    2. @Constraint(validatedBy = { ListValueConstraintValidator.class })
    3. @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    4. @Retention(RUNTIME)
    5. public @interface ListValue {
    6. String message() default "{com.atguigu.common.valid.ListValue.message}";
    7. Class<?>[] groups() default { };
    8. Class<? extends Payload>[] payload() default { };
    9. int[] vals() default { };
    10. }
  • 创建校验器

    1. public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
    2. private Set<Integer> set = new HashSet<>();
    3. @Override
    4. public void initialize(ListValue constraintAnnotation) {
    5. int[] vals = constraintAnnotation.vals();
    6. for (int val : vals) {
    7. set.add(val);
    8. }
    9. }
    10. /**
    11. * @param value 需要校验的值
    12. * @param context
    13. * @return
    14. */
    15. @Override
    16. public boolean isValid(Integer value, ConstraintValidatorContext context) {
    17. return set.contains(value);
    18. }
    19. }

    全局异常处理

    集中处理控制器中抛出的异常,例如处理 JSR-303数据校验异常
    com/atguigu/gulimall/product/exception/GulimallExceptionControllerAdvice.java

    1. /**
    2. * 集中处理所有异常
    3. */
    4. @Slf4j
    5. @RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
    6. public class GulimallExceptionControllerAdvice {
    7. @ExceptionHandler(value = MethodArgumentNotValidException.class)
    8. public R handleVaildException(MethodArgumentNotValidException e) {
    9. log.error("数据校验出现问题{},异常类型:{}", e.getMessage(), e.getClass());
    10. BindingResult bindingResult = e.getBindingResult();
    11. Map<String, String> errorMap = new HashMap<>();
    12. bindingResult.getFieldErrors().forEach((fieldError) -> {
    13. errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
    14. });
    15. return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(), BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data", errorMap);
    16. }
    17. }

    SKU 与SPU

    电商系统中的sku与spu