项目10:springcloud组件的加入

项目10:springcloud组件的加入

1.nacos加入服务注册中心管理

2.openfeign远程调用服务

3.sentinel服务熔断

4.gateway网关的设定

5.跨域问题和跨域问题解决方案

项目10:springcloud组件的加入

1.加入服务注册中心管理

①结果

在这里插入图片描述

②引入pom(在service-base中)

        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>

③在所有微服务的application.yml配置

#spring
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos服务地址

④在主启动类中开启服务发现

@EnableDiscoveryClient

2.openfeign远程调用服务

①实现功能

  • 未加入远程调用:注册发送短信,然后前端封装一个注册对象到后端,后端用整个注册对象去查数据库,有了返回手机号已经存在。
  • 优化:在注册发送短信时就判断手机号是否注册,如果没注册则不发送短信并且返回结果
  • openfeign服务流程
    即在sms发送短信服务中远程调用core服务的校验手机号是否已经注册服务,然后再前端调用发送短信服务时判断是否注册
    项目10:springcloud组件的加入_第1张图片

②引入openfeign依赖

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-openfeignartifactId>
        dependency>

③openfeign调用的服务

  • core中判断手机号是否注册服务
@Api(tags = "会员接口")
@RestController
@RequestMapping("/api/core/userInfo")
@Slf4j
@CrossOrigin
public class UserInfoController {
 /**
     * @param mobile:
     * @return R
     * @author Likejin
     * @description 短信服务远程调用,在发短信前检测号码是否被注册
     * @date 2023/4/14 9:33
     */

    @ApiOperation("校验手机号是否注册")
    @GetMapping("/checkMobile/{mobile}")
    public Boolean checkMobile(@PathVariable String mobile){
        boolean result = userInfoService.checkMobile(mobile);
        return result;

    }

}


/**
 * 

* 用户基本信息 服务类 *

* * @author Likejin * @since 2023-04-09 */
public interface UserInfoService extends IService<UserInfo> { boolean checkMobile(String mobile); }
/**
 * 

* 用户基本信息 服务实现类 *

* * @author Likejin * @since 2023-04-09 */
@Service public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService { /** * @param mobile: * @return boolean * @author Likejin * @description 校验手机号是否存在 * @date 2023/4/14 9:38 */ @Override public boolean checkMobile(String mobile) { QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>(); userInfoQueryWrapper.eq("mobile",mobile); Integer count = baseMapper.selectCount(userInfoQueryWrapper); return count>0; } }

④openfeign客户端

  • 开启openfeign客户端
@SpringBootApplication
//项目直接的互相调用,可以直接扫描到(不要写到具体包下,写到项目下即可)
@ComponentScan({"com.atguigu.srb","com.atguigu.common"})

@EnableDiscoveryClient
@EnableFeignClients
public class ServiceSmsApplication {

    public static void main(String[] args) {
            SpringApplication.run(ServiceSmsApplication.class, args);

    }
}
  • 写一个远程调用接口
package com.atguigu.srb.sms.client;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;


@FeignClient(value ="service-core")
public interface CoreUserInfoClient {
    @GetMapping("/api/core/userInfo/checkMobile/{mobile}")
    //远程调用,此处必须加上@PathVariable("mobile") 否则运行不成功
    Boolean checkMobile(@PathVariable("mobile") String mobile);
}


  • 服务中具体实现远程调用
package com.atguigu.srb.sms.controller.api;


import com.atguigu.common.exception.Assert;
import com.atguigu.common.result.R;
import com.atguigu.common.result.ResponseEnum;
import com.atguigu.common.util.RandomUtils;
import com.atguigu.common.util.RegexValidateUtils;
import com.atguigu.srb.sms.client.CoreUserInfoClient;
import com.atguigu.srb.sms.service.SmsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/api/sms")
@Api(tags = "短信管理")
@CrossOrigin //跨域
@Slf4j
public class ApiSmsController {

    @Resource
    private SmsService smsService;

    @Resource
    private CoreUserInfoClient coreUserInfoClient;

    @Resource
    private RedisTemplate redisTemplate;

    @ApiOperation("获取验证码")
    @GetMapping("/send/{mobile}")
    public R send(
            @ApiParam(value = "手机号", required = true)
            @PathVariable String mobile){

        //MOBILE_NULL_ERROR(-202, "手机号不能为空"),
        Assert.notEmpty(mobile, ResponseEnum.MOBILE_NULL_ERROR);
        //MOBILE_ERROR(-203, "手机号不正确"),
        Assert.isTrue(RegexValidateUtils.checkCellphone(mobile), ResponseEnum.MOBILE_ERROR);


        //判断手机号是否已经注册(要操作service-core中的微服务)

        Boolean result = coreUserInfoClient.checkMobile(mobile);
        Assert.isTrue(result==false,ResponseEnum.MOBILE_EXIST_ERROR);
        //希望能够看到远程调用的日志
        log.info("result",result);

        //生成验证码
        String code = RandomUtils.getFourBitRandom();
        //组装短信模板参数
        Map<String,Object> param = new HashMap<>();
        param.put("code", code);
        //发送短信
        //测试过程中停掉具体发送短信,只需要在redis中获得验证码即可
        //smsService.send(mobile, SmsProperties.TEMPLATE_CODE, param);

        //将验证码存入redis
        redisTemplate.opsForValue().set("srb:sms:code:" + mobile, code, 5, TimeUnit.MINUTES);

        return R.ok().message("短信发送成功");
    }
}

⑤openfeign的超时配置

feign:
  client:
    config:
      default:
        connectTimeout: 10000 #连接超时配置
        readTimeout: 600000 #执行超时配置

⑥openfeign日志控制

  • 配置openfeign日志全局控制器
package com.atguigu.srb.base.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OpenFeignConfig {

    //指定最高级别的日志配置
    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}
  • yml中配置日志级别(在sms即openfeign的客户端)
logging:
  level:
    com.atguigu.srb.sms.client.CoreUserInfoClient: DEBUG #以什么级别监控哪个接口
  • 修改日志监控级别

    
    
    
    <springProfile name="dev,test">
        <logger name="com.atguigu" level="DEBUG">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="ROLLING_FILE" />
        logger>
    springProfile>

3.sentinel服务熔断

①实现

  • 如果core服务宕机,那么sms服务发短信服务不能一直等待,需要有兜底方法
  • 功能:
    如果连接不到core服务,那么就不进行手机号校验,执行兜底方法,直接发送验证码给用户然后在提交时校验

②引入依赖(service-base)

        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
        dependency>

③配置feign支持服务熔断

#feign:
  sentinel:
    enabled: true

④配置兜底方法

package com.atguigu.srb.sms.client;

import com.atguigu.srb.sms.client.fallback.CoreUserInfoClientFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

//熔断功能没有使用
@FeignClient(value ="service-core",fallback = CoreUserInfoClientFallback.class)
public interface CoreUserInfoClient {
    @GetMapping("/api/core/userInfo/checkMobile/{mobile}")
    //远程调用,此处必须加上@PathVariable("mobile") 否则运行不成功
    Boolean checkMobile(@PathVariable("mobile") String mobile);
}


package com.atguigu.srb.sms.client.fallback;

import com.atguigu.srb.sms.client.CoreUserInfoClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;


@Service
@Slf4j
public class CoreUserInfoClientFallback implements CoreUserInfoClient {
    @Override
    public Boolean checkMobile(String mobile) {
        log.error("远程调用失败,服务熔断");
        return false;//手机号不重复
    }
}

4.gateway网关的设定

①功能

  • 之前前端访问后端(nginx)
    • 跨域用@CrossOrigin解决。
      项目10:springcloud组件的加入_第2张图片
    • 前端访问http:localhost/admin/core/integralGrade/list
      nginx转发到。http:localhost:8110/admin/core/integralGrade/list
    • ajax请求需要配置跨域,在controller中加入@CrossOrigin解决。
  • 正常功能
    • nginx配置反向代理访问前端,前端通过gateway访问后端。
      跨域用gatewat的配置。
    • 前端访问http://localhost/admin/core/integralGrade/list
    • gateway转发到http://localhost/admin/core/integralGrade/list(gateway配置了路由,gateway自动路由应该是http://网关地址:网关端口/service名称/路由地址:例子:http://localhost/service-core/admin/core/integralGrade/list)
    • 配置跨域
      即ajax请求访问到gateway(跨域请求),gateway转发到各个微服务,在gateway中配置跨域

②配置gateway微服务(引入依赖)


<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">
    <parent>
        <artifactId>srbartifactId>
        <groupId>com.atguigugroupId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <modelVersion>4.0.0modelVersion>

    <artifactId>service-gatewayartifactId>
    <dependencies>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-gatewayartifactId>
        dependency>
        
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
        dependency>
    dependencies>

project>

③gateway微服务的application.yml

server:
  port: 80 # 服务端口

spring:
  profiles:
    active: dev # 环境设置
  application:
    name: service-gateway # 服务名
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos服务地址
    gateway:
      discovery:
        locator:
          enabled: true # gateway可以发现nacos中的微服务,并自动生成转发路由
      routes:
      - id: service-core #自动找service-core微服务
        uri: lb://service-core #路由到service-core
        predicates:
        - Path=/*/core/** #如果地址第二个为core
      - id: service-sms
        uri: lb://service-sms
        predicates:
        - Path=/*/sms/**
      - id: service-oss
        uri: lb://service-oss
        predicates:
        - Path=/*/oss/**
  • logback改名为gateway即可

④主启动

package com.atguigu.srb.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class ServiceGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceGatewayApplication.class, args);
    }
}

⑤配置跨域(删除之前所有微服务使用的跨域注解@CrossOrigin )

package com.atguigu.srb.gateway.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

@Configuration
public class CorsConfig {
    //配置跨域请求,然后设置策略来是否允许跨域
    @Bean
    public CorsWebFilter corsFilter() {

        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); //是否允许携带cookie,允许cookie跨域
        config.addAllowedOrigin("*"); //可接受的域,是一个具体域名或者*(代表任意域名)
        config.addAllowedHeader("*"); //允许携带的头
        config.addAllowedMethod("*"); //允许访问的方式
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config); //注册配置项config,针对所有url地址都用config的策略
        return new CorsWebFilter(source);
    }
}

5.跨域问题和跨域问题解决方案

①什么是跨域问题?

  • 前端后端交互时前端页面和后端服务不在同一个机器下的端口下,默认浏览器会设定为跨域访问。

②怎么才是跨域呢?

  • 浏览器键入URL是跨域吗?
    不是跨域,浏览器键入URL属于客户端和服务器交互,而不是页面与服务器交互。
  • href标签涉及跨域吗?
    href标签也不涉及跨域,因为href标签相当于网页跳转,与本页面无关。
  • ajax请求跨域吗?
    具体为网页向服务器发起请求,故ajax涉及跨域。

③跨域请求流程

  • 浏览器发起请求
  • 浏览器先检查该请求是否会跨域请求(判断目的主机和本主机的ip和端口号)
    不是跨域直接发送出去。
    是跨域请求则在请求头中增加origin字段表明请求从哪里发出。
  • 服务器接受请求
  • 服务器给出响应
    响应header里写明跨域的配置信息,表明自己可以接受哪些域名的请求访问。

④跨域问题的解决方案

  • 使用 @CrossOrigin 注解实现跨域
  • 通过 CorsFilter 对象实现跨域
  • 两者选一个使用即可
    更改响应头

未更新

未更新

未更新

未更新

未更新

未更新

未更新

未更新

未更新

你可能感兴趣的:(项目1:金融借钱还钱,spring,cloud,java,spring)