springcloud项目搭建

springcloud项目搭建

搭建父工程

首先先创建父工程,删除src文件夹,并在pom中进行子项目的版本控制

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.22</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.3</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.3.3.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR8</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.16</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.3.RELEASE</version>
            </plugin>
        </plugins>
    </build>

搭建eureka

maven

右键单击父工程–>new–>modules,新建eureka工程
maven核心依赖:

<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>

yml文件

resource下新建application.yml文件

spring:
  profiles:
    active: default
---
server:
  port: 8761 #指定运行端口
spring:
  application:
    name: eureka-server #指定服务名称
  profiles: default
eureka:
  instance:
    hostname: localhost #指定主机地址
  client:
    fetch-registry: false #指定是否要从注册中心获取服务(默认true)
    register-with-eureka: false #指定是否要注册到注册中心(默认true)
  server:
    enable-self-preservation: false #是否开启保护模式(默认true)
    eviction-interval-timer-in-ms: 3000 # 清理间隔(单位毫秒,默认是60*1000)
logging:
  level:
    com.netflix: warn
---
spring:
  application:
    name: eureka-cluster #指定服务名称
  profiles: eureka1
server:
  port: 8011 #指定运行端口
eureka:
  instance:
    hostname: localhost #指定主机地址
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
  client:
    register-with-eureka: true #指定是否要注册到注册中心(默认true)
    fetch-registry: true #指定是否要从注册中心获取服务(默认true)
    serviceUrl:
      defaultZone: http://localhost:8012/eureka/,http://localhost:8013/eureka/ #注册到另一个Eureka注册中心
  server:
    enable-self-preservation: false #是否开启保护模式(默认true)
    eviction-interval-timer-in-ms: 3000 # 清理无效服务节点的时间间隔(单位毫秒,默认是60*1000)
logging:
  level:
    com.netflix: warn
---
spring:
  application:
    name: eureka-cluster #指定服务名称
  profiles: eureka2
server:
  port: 8012 #指定运行端口
eureka:
  instance:
    hostname: localhost #指定主机地址
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
  client:
    register-with-eureka: true #指定是否要注册到注册中心(默认true)
    fetch-registry: true #指定是否要从注册中心获取服务(默认true)
    serviceUrl:
      defaultZone: http://localhost:8011/eureka/,http://localhost:8013/eureka/ #注册到另一个Eureka注册中心
  server:
    enable-self-preservation: false #是否开启保护模式(默认true)
    eviction-interval-timer-in-ms: 3000 # 清理无效服务节点的时间间隔(单位毫秒,默认是60*1000)
logging:
  level:
    com.netflix: warn
---
spring:
  application:
    name: eureka-cluster #指定服务名称
  profiles: eureka3
server:
  port: 8013 #指定运行端口
eureka:
  instance:
    hostname: localhost #指定主机地址
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
  client:
    register-with-eureka: true #指定是否要注册到注册中心(默认true)
    fetch-registry: true #指定是否要从注册中心获取服务(默认true)
    serviceUrl:
      defaultZone: http://localhost:8012/eureka/,http://localhost:8011/eureka/ #注册到另一个Eureka注册中心
  server:
    enable-self-preservation: false #是否开启保护模式(默认true)
    eviction-interval-timer-in-ms: 3000 # 清理无效服务节点的时间间隔(单位毫秒,默认是60*1000)
logging:
  level:
    com.netflix: warn

启动类

新建EurekaApplication启动类,在类上添加@EnableEurekaServer注解

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

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

测试

启动eureka,启动成功后访问http://localhost:8761/,出现以下界面则eureka配置成功
在这里插入图片描述

zuul网关

maven

新建zuul子工程,添加maven核心依赖

		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

将其加入eureka服务中心

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>

yml文件

spring:
  application:
    name: zuul-proxy   #服务名

server:
  port: 10000    # 端口

#注册中心相关配置
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    instance-id: ${spring.cloud.client.ip-address}:${server.port}

#网关配置
zuul:
#    LogFilter:    #自定义过滤器的名称
#      pre:        #自定义过滤器类型
#        disable: true  # 是否禁用
  prefix: /api/      #前缀
  routes:   #路由规则
    user:
      path: /u/**
      url: http://localhost:8102    #远程服务必须有url
    permission:
      path: /p/**
    student:
      path: /s/**
# 关闭那些服务的默认路由  
  ignored-services: permission,user,student   

  add-host-header: true
  #不对敏感资源做拦截
  sensitive-headers:
  ignored-headers:
  host:
    socket-timeout-millis: 4000 # 请求的处理时间
    connect-timeout-millis: 4000 # 请求的链接时间
#开启路由端点
management:
  endpoints:
    web:
      exposure:
        include: 'routes'

ZuulApplication

类上添加@EnableDiscoveryClient,@EnableZuulProxy注解

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

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

启动ZuulApplication,启动完成后刷新eureka
在这里插入图片描述
显示如图则配置成功

config配置中心(需要gitee)

config服务端

maven

新建config子工程,添加核心依赖

	<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
        <version>2.2.5.RELEASE</version>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.2.5.RELEASE</version>
    </dependency>

如果要使用消息总线则添加rabbitMQ依赖

     <!--配置rabbitMQ开始-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>

yml文件

server:
  port: 8901
spring:
  application:
    name: config-server
  rabbitmq: #rabbitmq相关配置
    host: localhost
    port: 5672
    username: guest
    password: guest
  cloud:
    config:
      server:
        git: #配置存储配置信息的Git仓库
          uri: https://gitee.com/wxkjpub/config-zhuchunsheng.git
          username: wxkjpub
          password: wxkj@123456
          clone-on-start: true #配置中心启动时直接从git获取配置
eureka:
  instance:
    hostname: localhost #指定主机地址
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
management:
  endpoints: #暴露bus刷新配置的端点
    web:
      exposure:
        include: 'bus-refresh'

启动类ConfigApplication

类上添加@EnableDiscoveryClient、@EnableConfigServer注解

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

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

启动ConfigApplication ,刷新eureka

被配置中心管理yml文件的项目

maven

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

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

添加额外yml配置

添加单个服务的刷新
#刷新配置
management:
  endpoints:
    web:
      exposure:
        include: 'refresh'
添加配置中心的的地址
spring:
  application:
    name: zuul
  cloud:
    #Config客户端配置
    config:
      #启用配置后缀名称
      profile: dev
      #分支名称
      label: master
      #配置中心地址
      uri: http://localhost:8901
      #配置文件名称
      name: zuul

security

新建security子项目,并添加核心依赖

maven

<dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

application.yml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://192.168.0.142:3306/springcloud?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
  application:
    name: security

eureka:
  instance:
    lease-renewal-interval-in-seconds: 5
    #续约更新时间间隔
    lease-expiration-duration-in-seconds: 15
    #续约更新时间间隔
    hostname: localhost
    #指定主机地址
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
  client:
    healthcheck:
      enabled: true
    register-with-eureka: true
    #注册到Eureka的注册中心
    fetch-registry: true
    #获取注册实例列表
    service-url:
      defaultZone:  http://localhost:8761/eureka
      #配置注册中心地址
    registry-fetch-interval-seconds: 10
    # 设置服务消费者从注册中心拉取服务列表的间隔

jwt:
  #定义我们的盐  密码
  secret: mySecret
  #过期时间
  expiration: 1
  #token 的类型 说明他以 bearer 开头
  tokenHead: bearer
  #token 对应的 key
  tokenHeader: Authorization
#  {Authorization: "bearer sdfdsfsdfsdfdsfsdfadfdsf"}

SecurityApplication

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

生成权限验证的token类

JwtTokenUtil

package com.wanxi.spring.cloud.security.commons;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * JwtToken生成的工具类
 * JWT token的格式:header.payload.signature
 * header的格式(算法、token的类型):
 * {"alg": "HS512","typ": "JWT"}
 * payload的格式(用户名、创建时间、生成时间):
 * {"sub":"wang","created":1489079981393,"exp":1489684781}
 * signature的生成算法:
 * HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
 * Created by wx on 2019/4/26.
 */
@Component
public class JwtTokenUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);
    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "created";
    private static final String CLAIM_KEY_AUTHORITY = "auth";

    @Value("${jwt.secret}")
    private String secret;
    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 根据负责生成JWT的token
     */
    private String generateToken(Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    /**
     * 从token中获取JWT中的负载
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            LOGGER.info("JWT格式验证失败:{}",token);
        }
        return claims;
    }

    /**
     * 生成token的过期时间
     */
    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    /**
     * 从token中获取登录用户名
     */
    public String getUserNameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username =  claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 验证token是否还有效
     * @param token       客户端传入的token
     * @param userDetails 从数据库中查询出来的用户信息
     */
    public boolean validateToken(String token, UserDetails userDetails) {
        String username = getUserNameFromToken(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }

    /**
     * 判断token是否已经失效
     */
    private boolean isTokenExpired(String token) {
        Date expiredDate = getExpiredDateFromToken(token);
        return expiredDate.before(new Date());
    }

    /**
     * 从token中获取过期时间
     */
    private Date getExpiredDateFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    /**
     * 根据用户信息生成token
     */
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
        Set<Object> collect = authorities.stream().filter(p -> StringUtils.hasText(p.getAuthority()))
                .map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
        claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
        claims.put(CLAIM_KEY_CREATED, new Date());
        claims.put(CLAIM_KEY_AUTHORITY,collect);
        return generateToken(claims);
    }

    /**
     * 判断token是否可以被刷新
     */
    public boolean canRefresh(String token) {
        return !isTokenExpired(token);
    }

    /**
     * 刷新token
     */
    public String refreshToken(String token) {
        Claims claims = getClaimsFromToken(token);
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }
}

设置跨域

FilterConfig

package com.wanxi.spring.cloud.security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
@Order(1)
public class FilterConfig {
    private CorsConfiguration buildConfig(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedHeader("*"); // 允许任何的head头部
        corsConfiguration.addAllowedOrigin("*"); // 允许任何域名使用
        corsConfiguration.addAllowedMethod("*"); // 允许任何的请求方法
        corsConfiguration.setAllowCredentials(true);
        return corsConfiguration;
    }
    // 添加CorsFilter拦截器,对任意的请求使用
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", buildConfig());
        return new CorsFilter(source);
    }
}

security配置类

package com.wanxi.spring.cloud.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http .cors().and()
                .csrf().disable()
                .sessionManagement()// 基于token,所以不需要 securityContext
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/css/**", "/js/**", "/fonts/**","/user/login","/user/login2").permitAll() //都可以访问
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .anyRequest().authenticated() // 任何请求都需要认证
                .and()
                .userDetailsService(userDetailsService)
        ; 
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

至此搭建基本完成

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值