当前位置: 首页 > news >正文

黑马头条微服务学习day01-环境搭建、SpringCloud微服务(注册发现、网关)

文章目录

  • 项目介绍
    • 环境搭建
    • 项目背景
    • 业务功能
    • 技术栈说明
  • nacos
    • 服务器环境准备
    • nacos安装
  • 初始工程搭建
    • 环境准备
    • 主体结构
  • app登录
    • 需求分析
    • 表结构分析
    • 手动加密
    • 微服务搭建
    • 接口定义
    • 功能实现
      • 登录功能实现
    • Swagger使用
    • app端网关
    • nginx配置

项目介绍

环境搭建

在这里插入图片描述
在这里插入图片描述

项目背景

在这里插入图片描述

业务功能


在这里插入图片描述

技术栈说明

在这里插入图片描述
在这里插入图片描述

nacos

可以直接参照各种虚拟机安装centos7,不必拘泥于课程所给的镜像,只要保证能与外界ping通即可。后续环境可以自行安装。
同时使用mac的m系列芯片的同学可以直接不使用虚拟机直接在本地下载docker配置环境(注意要适配ARM架构)。

服务器环境准备

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

nacos安装

在这里插入图片描述
在这里插入图片描述

初始工程搭建

环境准备

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
配置Maven
在这里插入图片描述

主体结构

在这里插入图片描述
在这里插入图片描述

app登录

需求分析

在这里插入图片描述

表结构分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过逆向工程生成

package com.heima.model.user.pojos;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.io.Serializable;
import java.util.Date;/*** <p>* APP用户信息表* </p>** @author itheima*/
@Data
@TableName("ap_user")
public class ApUser implements Serializable {private static final long serialVersionUID = 1L;/*** 主键*/@TableId(value = "id", type = IdType.AUTO)private Integer id;/*** 密码、通信等加密盐*/@TableField("salt")private String salt;/*** 用户名*/@TableField("name")private String name;/*** 密码,md5加密*/@TableField("password")private String password;/*** 手机号*/@TableField("phone")private String phone;/*** 头像*/@TableField("image")private String image;/*** 0 男1 女2 未知*/@TableField("sex")private Boolean sex;/*** 0 未1 是*/@TableField("is_certification")private Boolean certification;/*** 是否身份认证*/@TableField("is_identity_authentication")private Boolean identityAuthentication;/*** 0正常1锁定*/@TableField("status")private Boolean status;/*** 0 普通用户1 自媒体人2 大V*/@TableField("flag")private Short flag;/*** 注册时间*/@TableField("created_time")private Date createdTime;}

手动加密

在这里插入图片描述
在这里插入图片描述

微服务搭建

在这里插入图片描述
在下面新建一个工程
在这里插入图片描述
bootstrap配置

server:port: 51801
spring:application:name: leadnews-usercloud:nacos:discovery:server-addr: 192.168.200.130:8848config:server-addr: 192.168.200.130:8848file-extension: yml

使用nacos创建新集群
在这里插入图片描述

spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/leadnews_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTCusername: rootpassword: root
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:mapper-locations: classpath*:mapper/*.xml# 设置别名包扫描路径,通过该属性可以给包中的类注册别名type-aliases-package: com.heima.model.user.pojos

配置logback.xml

<?xml version="1.0" encoding="UTF-8"?><configuration><!--定义日志文件的存储地址,使用绝对路径--><property name="LOG_HOME" value="e:/logs"/><!-- Console 输出设置 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern><charset>utf8</charset></encoder></appender><!-- 按照每天生成日志文件 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--日志文件输出的文件名--><fileNamePattern>${LOG_HOME}/leadnews.%d{yyyy-MM-dd}.log</fileNamePattern></rollingPolicy><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><!-- 异步输出 --><appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender"><!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 --><discardingThreshold>0</discardingThreshold><!-- 更改默认的队列的深度,该值会影响性能.默认值为256 --><queueSize>512</queueSize><!-- 添加附加的appender,最多只能添加一个 --><appender-ref ref="FILE"/></appender><logger name="org.apache.ibatis.cache.decorators.LoggingCache" level="DEBUG" additivity="false"><appender-ref ref="CONSOLE"/></logger><logger name="org.springframework.boot" level="debug"/><root level="info"><!--<appender-ref ref="ASYNC"/>--><appender-ref ref="FILE"/><appender-ref ref="CONSOLE"/></root>
</configuration>

在这里插入图片描述

接口定义

在这里插入图片描述
在这里插入图片描述

功能实现

登录功能实现

下面分Controller,Service,ServiceImpl层,与Mapper层依次输入代码

@RestController
@RequestMapping("/api/v1/login")
public class ApUserLoginController {@Autowiredprivate APUserService apUserService;@PostMapping("/login_auth")public ResponseResult login(@RequestBody LoginDto dto){return apUserService.login(dto);}
}
package com.heima.user.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.user.dtos.LoginDto;
import com.heima.model.common.user.pojos.ApUser;public interface APUserService extends IService<ApUser> {/*** app端登录功能* @param dto* @return*/public ResponseResult login(LoginDto dto);
}
@Service
@Transactional
@Slf4j
/*** ApUserMapper:这是一个 MyBatis-Plus 的 Mapper 接口,通常用于定义数据库操作的方法。* ApUser:这是一个实体类,表示数据库中的一张表。*/
public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser> implements APUserService {/*** app登录功能* @param dto* @return*/@Overridepublic ResponseResult login(LoginDto dto) {//1.正常登录用户用户名和密码if (StringUtils.isNotEmpty(dto.getPhone())&&StringUtils.isNotEmpty(dto.getPassword())){//1.1根据手机号从数据库中查询用户信息ApUser dbUser = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, dto.getPhone()));if (dbUser == null){return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"用户信息不存在");}//1.2比对密码String salt = dbUser.getSalt();String password = dto.getPassword();String pswd = DigestUtils.md5DigestAsHex((password + salt).getBytes());if (!pswd.equals(dbUser.getPassword())){return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);}//1.3 返回数据jwt userString token = AppJwtUtil.getToken(dbUser.getId().longValue());//跟接口返回值描述保持一致Map<String, Object> map = new HashMap<>();map.put("token",token);dbUser.setSalt("");dbUser.setPassword("");map.put("user",dbUser);return ResponseResult.okResult(map);}else {//2.游客登录Map<String,Object> map = new HashMap<>();map.put("token",AppJwtUtil.getToken(0L));return ResponseResult.okResult(map);}}
}
@Mapper
public interface ApUserMapper extends BaseMapper<ApUser> {}

使用接口工具类进行测试
在这里插入图片描述

Swagger使用

在这里插入图片描述
在这里插入图片描述

  • 引入依赖,在heima-leadnews-model和heima-leadnews-common模块中引入该依赖

    <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId>
    </dependency>
    <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId>
    </dependency>
    

只需要在heima-leadnews-common中进行配置即可,因为其他微服务工程都直接或间接依赖即可。

  • 在heima-leadnews-common工程中添加一个配置类

新增:com.heima.common.swagger.SwaggerConfiguration

package com.heima.common.swagger;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.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;@Configuration
@EnableSwagger2
public class SwaggerConfiguration {@Beanpublic Docket buildDocket() {return new Docket(DocumentationType.SWAGGER_2).apiInfo(buildApiInfo()).select()// 要扫描的API(Controller)基础包.apis(RequestHandlerSelectors.basePackage("com.heima")).paths(PathSelectors.any()).build();}private ApiInfo buildApiInfo() {Contact contact = new Contact("黑马程序员","","");return new ApiInfoBuilder().title("黑马头条-平台管理API文档").description("黑马头条后台api").contact(contact).version("1.0.0").build();}
}

在heima-leadnews-common模块中的resources目录中新增以下目录和文件

文件:resources/META-INF/Spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.heima.common.swagger.SwaggerConfiguration

给Controller和DTO更新注解

@RestController
@RequestMapping("/api/v1/login")
@Api(value = "app端用户登录",tags = "app端用户登录")
public class ApUserLoginController {@Autowiredprivate ApUserService apUserService;@PostMapping("/login_auth")@ApiOperation("用户登录")public ResponseResult login(@RequestBody LoginDto dto){return apUserService.login(dto);}}
@Data
public class LoginDto {/*** 手机号*/@ApiModelProperty(value = "手机号",required = true)private String phone;/*** 密码*/@ApiModelProperty(value = "密码",required = true)private String password;
}

打开Swagger
在这里插入图片描述
在这里插入图片描述

app端网关

在这里插入图片描述
在这里插入图片描述
(1)在heima-leadnews-gateway导入以下依赖

pom文件

<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId></dependency>
</dependencies>

(2)在heima-leadnews-gateway下创建heima-leadnews-app-gateway微服务

引导类:

package com.heima.app.gateway;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
@EnableDiscoveryClient  //开启注册中心
public class AppGatewayApplication {public static void main(String[] args) {SpringApplication.run(AppGatewayApplication.class,args);}
}

bootstrap.yml

server:port: 51601
spring:application:name: leadnews-app-gatewaycloud:nacos:discovery:server-addr: 192.168.200.130:8848config:server-addr: 192.168.200.130:8848file-extension: yml

在nacos的配置中心创建dataid为leadnews-app-gateway的yml配置

spring:cloud:gateway:globalcors:add-to-simple-url-handler-mapping: truecorsConfigurations:'[/**]':allowedHeaders: "*"allowedOrigins: "*"allowedMethods:- GET- POST- DELETE- PUT- OPTIONroutes:# 平台管理- id: useruri: lb://leadnews-userpredicates:- Path=/user/**filters:- StripPrefix= 1

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

bootstrap

server:port: 51601
spring:application:name: leadnews-app-gatewaycloud:nacos:discovery:server-addr: localhost:8848config:server-addr: localhost:8848file-extension: yml

设置权限过滤器

package com.heima.app.gateway.filter;import com.heima.app.gateway.util.AppJwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Component
@Slf4j
public class AuthorizeFilter implements Ordered, GlobalFilter {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//1.获取Request和Response对象ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();//2.判断是否登录if (request.getURI().getPath().contains("/login")){//放行return chain.filter(exchange);}//3.获取tokenString token = request.getHeaders().getFirst("token");//4.判断token是否存在if (StringUtils.isBlank(token)){response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}//5.判断token是否有效try {Claims claimsBody = AppJwtUtil.getClaimsBody(token);//是否是过期int result = AppJwtUtil.verifyToken(claimsBody);if (result==1 || result==2) {response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}}catch (Exception e){e.printStackTrace();response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}//6.放行return chain.filter(exchange);}/*** 优先级设置: 值越小 优先级越高* @return*/@Overridepublic int getOrder() {return 0;}
}
package com.heima.app.gateway.util;import io.jsonwebtoken.*;import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;public class AppJwtUtil {// TOKEN的有效期一天(S)private static final int TOKEN_TIME_OUT = 3_600;// 加密KEYprivate static final String TOKEN_ENCRY_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY";// 最小刷新间隔(S)private static final int REFRESH_TIME = 300;// 生产IDpublic static String getToken(Long id){Map<String, Object> claimMaps = new HashMap<>();claimMaps.put("id",id);long currentTime = System.currentTimeMillis();return Jwts.builder().setId(UUID.randomUUID().toString()).setIssuedAt(new Date(currentTime))  //签发时间.setSubject("system")  //说明.setIssuer("heima") //签发者信息.setAudience("app")  //接收用户.compressWith(CompressionCodecs.GZIP)  //数据压缩方式.signWith(SignatureAlgorithm.HS512, generalKey()) //加密方式.setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000))  //过期时间戳.addClaims(claimMaps) //cla信息.compact();}/*** 获取token中的claims信息** @param token* @return*/private static Jws<Claims> getJws(String token) {return Jwts.parser().setSigningKey(generalKey()).parseClaimsJws(token);}/*** 获取payload body信息** @param token* @return*/public static Claims getClaimsBody(String token) {try {return getJws(token).getBody();}catch (ExpiredJwtException e){return null;}}/*** 获取hearder body信息** @param token* @return*/public static JwsHeader getHeaderBody(String token) {return getJws(token).getHeader();}/*** 是否过期** @param claims* @return -1:有效,0:有效,1:过期,2:过期*/public static int verifyToken(Claims claims) {if(claims==null){return 1;}try {
//            claims.getExpiration()
//                    .before(new Date());// 需要自动刷新TOKENif((claims.getExpiration().getTime()-System.currentTimeMillis())>REFRESH_TIME*1000){return -1;}else {return 0;}} catch (ExpiredJwtException ex) {return 1;}catch (Exception e){return 2;}}/*** 由字符串生成加密key** @return*/public static SecretKey generalKey() {byte[] encodedKey = Base64.getEncoder().encode(TOKEN_ENCRY_KEY.getBytes());SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;}public static void main(String[] args) {/* Map map = new HashMap();map.put("id","11");*/System.out.println(AppJwtUtil.getToken(1102L));Jws<Claims> jws = AppJwtUtil.getJws("eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAADWLQQqEMAwA_5KzhURNt_qb1KZYQSi0wi6Lf9942NsMw3zh6AVW2DYmDGl2WabkZgreCaM6VXzhFBfJMcMARTqsxIG9Z888QLui3e3Tup5Pb81013KKmVzJTGo11nf9n8v4nMUaEY73DzTabjmDAAAA.4SuqQ42IGqCgBai6qd4RaVpVxTlZIWC826QA9kLvt9d-yVUw82gU47HDaSfOzgAcloZedYNNpUcd18Ne8vvjQA");Claims claims = jws.getBody();System.out.println(claims.get("id"));}}

nginx配置

在这里插入图片描述
在这里插入图片描述
①:解压资料文件夹中的压缩包nginx-1.18.0.zip

②:解压资料文件夹中的前端项目app-web.zip

③:配置nginx.conf文件

在nginx安装的conf目录下新建一个文件夹leadnews.conf,在当前文件夹中新建heima-leadnews-app.conf文件

heima-leadnews-app.conf配置如下:

upstream  heima-app-gateway{server localhost:51601;
}server {listen 8801;location / {root D:/workspace/app-web/;index index.html;}location ~/app/(.*) {proxy_pass http://heima-app-gateway/$1;proxy_set_header HOST $host;  # 不改变源请求头的值proxy_pass_request_body on;  #开启获取请求体proxy_pass_request_headers on;  #开启获取请求头proxy_set_header X-Real-IP $remote_addr;   # 记录真实发出请求的客户端IPproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  #记录代理信息}
}

nginx.conf 把里面注释的内容和静态资源配置相关删除,引入heima-leadnews-app.conf文件加载

#user  nobody;
worker_processes  1;events {worker_connections  1024;
}
http {include       mime.types;default_type  application/octet-stream;sendfile        on;keepalive_timeout  65;# 引入自定义配置文件include leadnews.conf/*.conf;
}

④ :启动nginx

​ 在nginx安装包中使用命令提示符打开,输入命令nginx启动项目

​ 可查看进程,检查nginx是否启动

​ 重新加载配置文件:nginx -s reload

⑤:打开前端项目进行测试 – > http://localhost:8801

​ 用谷歌浏览器打开,调试移动端模式进行访问
在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【自动驾驶/机器人面试C++八股精选】专栏介绍
  • Java技术栈总结:kafka篇
  • 大模型高效参数微调技术
  • Bilibili Android一二面凉经(2024)
  • jenkins系列-06.harbor
  • 微软Win11 24H2七月更新补丁KB5040435发布!附下载
  • Python库 - Scrapy
  • AI机器人在未来的应用场景预测:是否会取代人类?华为、百度、特斯拉他们在AI领域都在做什么?
  • .env.development、.env.production、.env.staging
  • 【MySQL 进阶】MySQL 程序 -- 详解
  • Vue 3中的v-for指令使用详解
  • Python量化交易学习——Part12:回归模型的典型应用
  • PostgreSQL 怎样处理数据仓库中维度表和事实表的关联性能?
  • 快速使用BRTR公式出具的大模型Prompt提示语
  • [Vulnhub] Tr0ll3 aircrack-ng+lynx
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • CentOS7 安装JDK
  • extjs4学习之配置
  • iOS 系统授权开发
  • IOS评论框不贴底(ios12新bug)
  • JavaScript新鲜事·第5期
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • 区块链分支循环
  • Mac 上flink的安装与启动
  • zabbix3.2监控linux磁盘IO
  • 阿里云移动端播放器高级功能介绍
  • 扩展资源服务器解决oauth2 性能瓶颈
  • # 透过事物看本质的能力怎么培养?
  • #Datawhale AI夏令营第4期#多模态大模型复盘
  • (1)(1.13) SiK无线电高级配置(五)
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (区间dp) (经典例题) 石子合并
  • (三分钟)速览传统边缘检测算子
  • (十七)Flink 容错机制
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (最完美)小米手机6X的Usb调试模式在哪里打开的流程
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .Net Core 中间件与过滤器
  • .net Signalr 使用笔记
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .NET3.5下用Lambda简化跨线程访问窗体控件,避免繁复的delegate,Invoke(转)
  • .net6 core Worker Service项目,使用Exchange Web Services (EWS) 分页获取电子邮件收件箱列表,邮件信息字段
  • .net中应用SQL缓存(实例使用)
  • @RestController注解的使用
  • @vueup/vue-quill使用quill-better-table报moduleClass is not a constructor
  • [ A*实现 ] C++,矩阵地图
  • [023-2].第2节:SpringBoot中接收参数相关注解
  • [Bug]使用gradio创建应用提示AttributeError: module ‘gradio‘ has no attribute ‘inputs‘
  • [C#]winform制作仪表盘好用的表盘控件和使用方法
  • [C][数据结构][树]详细讲解
  • [FlareOn6]Overlong
  • [flutter]一键将YAPI生成的api.json文件转为需要的Dart Model类的脚本
  • [HNOI2008]水平可见直线
  • [JavaEE]线程的状态与安全
  • [JS]Math.random()随机数的二三事