- 个人主页:VON
- 文章所属专栏:黑马头条
- 个人唯一微信:微信
有一起学习微服务的小伙伴可以加作者微信:单击即可添加
目录
一、前言
二、项目概述
1、技术栈
2、项目引入
三、改造项目
1、创建heima-leadnews-user
2、创建实体类
3、改造heima-leadnews-user
(1)UserApplication引导类
(2)bootstrap.yml配置文件
(3)nacos配置
(4)logback.xml
4、功能实现
(1)controller层
(2)service层
(3)mapper层
(4)接口测试工具
四、网关
1、创建heima-leadnews-app-gateway
2、改造模块
(1)实体类
(2)bootstrap.yml配置文件
(3)nacos配置
(4)配置过滤器
3、部署前端项目
(1)创建存放conf的目录
(2)创建APP端conf
(3)改造conf文件
(4)改造原本的conf文件
4、测试
结语
一、前言
历时2552分钟将黑马商城项目拆分完毕,上述是学习时间表,黑马商城项目的更新先暂停一下,因为后续大都是知识点了,几乎也没有代码部分的东西了。另一方面也是因为快开学了,所以我还是想学点有关代码的知识,因此从今天开始学习黑马头条。
计划开学前将黑马头条完结,昨天其实已经开始了,只不过配置环境有点复杂,我这里大都是用的之前下载好的软件,并没有严格对标课程。本系列不再讲解有关环境配置方面的问题,如果有疑问就去直接看视频或者是看之前的文章就行。
废话不多说我就简单总结回顾一下我感觉有用的一些知识点。
特别声明:本系列所涉及资料皆为黑马程序员课程中的资料
二、项目概述
1、技术栈
这里是用到的相关技术,了解一下即可,后续都会有讲解
- Spring-Cloud-Gateway : 微服务之前架设的网关服务,实现服务注册中的API请求路由,以及控制流速控制和熔断处理都是常用的架构手段,而这些功能Gateway天然支持
- 运用Spring Boot快速开发框架,构建项目工程;并结合Spring Cloud全家桶技术,实现后端个人中心、自媒体、管理中心等微服务。
- 运用Spring Cloud Alibaba Nacos作为项目中的注册中心和配置中心
- 运用mybatis-plus作为持久层提升开发效率
- 运用Kafka完成内部系统消息通知;与客户端系统消息通知;以及实时数据计算
- 运用Redis缓存技术,实现热数据的计算,提升系统性能指标
- 使用Mysql存储用户数据,以保证上层数据查询的高性能
- 使用Mongo存储用户热数据,以保证用户热数据高扩展和高性能指标
- 使用FastDFS作为静态资源存储器,在其上实现热静态资源缓存、淘汰等功能
- 运用Hbase技术,存储系统中的冷数据,保证系统数据的可靠性
- 运用ES搜索技术,对冷数据、文章数据建立索引,以保证冷数据、文章查询性能
- 运用AI技术,来完成系统自动化功能,以提升效率及节省成本。比如实名认证自动化
- PMD&P3C : 静态代码扫描工具,在项目中扫描项目代码,检查异常点、优化点、代码规范等,为开发团队提供规范统一,提升项目代码质量
2、项目引入
将资料中的项目拷贝到本地
这里说明一下,我拷贝的时候并没有log文件,需要自己创建出来,和其他模块同级别创建即可,下面会有一个地方需要改动,等会再说
这里的版本改成我这样就不会报错了
这两个别忘了启动,数据库中表的导入我就不多说了
这里的数据库也可以换成本地数据库
jdk全部换成1.8
编码全部改为utf-8
这里换成资料中的仓库就不用再下载其他依赖了,特别方便建议改一下,当然不改也没事
三、改造项目
上述准备工作完成后就开始改造项目了
1、创建heima-leadnews-user
要看好位置再创建,创建完成后按照我的目录结构创建相应的包结构
一定不要放错位置
2、创建实体类
一定要看好位置再创建
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;}
3、改造heima-leadnews-user
(1)UserApplication引导类
package com.heima.user;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.user.mapper")
public class UserApplication {public static void main(String[] args) {org.springframework.boot.SpringApplication.run(UserApplication.class, args);}
}
(2)bootstrap.yml配置文件
这里的addr换成自己的nacos地址,也就是运行nacos的虚拟机地址+端口号
server:port: 51801
spring:application:name: leadnews-usercloud:nacos:discovery:server-addr: 192.168.73.134:8848config:server-addr: 192.168.73.134:8848file-extension: yml
(3)nacos配置
为了防止重复配置所以将公共部分抽取到nacos中了,有不会配置的参考下这篇文章👇
重生之我在暑假学习微服务第十一天《配置篇》+网关篇错误订正
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/leadnews_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=falseusername: rootpassword: 123456
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:mapper-locations: classpath*:mapper/*.xml# 设置别名包扫描路径,通过该属性可以给包中的类注册别名type-aliases-package: com.heima.model.user.pojos
(4)logback.xml
还记得上文提到的日志吗,这里改成./logs就行,将日志放在此文件夹下
<?xml version="1.0" encoding="UTF-8"?><configuration><!--定义日志文件的存储地址,使用绝对路径--><property name="LOG_HOME" value="./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>
4、功能实现
这里就是一个简单的登录功能的实现,就按照123的顺序讲解了
(1)controller层
这里我画住的地方先不用写,这是用来测试的接口工具
这里要引入一个实体类
实体类代码👇
package com.heima.model.user.dtos;import lombok.Data;@Data
public class LoginDto {//手机号private String phone;//密码private String password;
}
(2)service层
实现类👇
一定要放好位置,位置千万不要错了
package com.heima.model.common.dtos;import com.alibaba.fastjson.JSON;
import com.heima.model.common.enums.AppHttpCodeEnum;import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** 通用的结果返回类* @param <T>*/
public class ResponseResult<T> implements Serializable {private String host;private Integer code;private String errorMessage;private T data;public ResponseResult() {this.code = 200;}public ResponseResult(Integer code, T data) {this.code = code;this.data = data;}public ResponseResult(Integer code, String msg, T data) {this.code = code;this.errorMessage = msg;this.data = data;}public ResponseResult(Integer code, String msg) {this.code = code;this.errorMessage = msg;}public static ResponseResult errorResult(int code, String msg) {ResponseResult result = new ResponseResult();return result.error(code, msg);}public static ResponseResult okResult(int code, String msg) {ResponseResult result = new ResponseResult();return result.ok(code, null, msg);}public static ResponseResult okResult(Object data) {ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS, AppHttpCodeEnum.SUCCESS.getErrorMessage());if(data!=null) {result.setData(data);}return result;}public static ResponseResult errorResult(AppHttpCodeEnum enums){return setAppHttpCodeEnum(enums,enums.getErrorMessage());}public static ResponseResult errorResult(AppHttpCodeEnum enums, String errorMessage){return setAppHttpCodeEnum(enums,errorMessage);}public static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums){return okResult(enums.getCode(),enums.getErrorMessage());}private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums, String errorMessage){return okResult(enums.getCode(),errorMessage);}public ResponseResult<?> error(Integer code, String msg) {this.code = code;this.errorMessage = msg;return this;}public ResponseResult<?> ok(Integer code, T data) {this.code = code;this.data = data;return this;}public ResponseResult<?> ok(Integer code, T data, String msg) {this.code = code;this.data = data;this.errorMessage = msg;return this;}public ResponseResult<?> ok(T data) {this.data = data;return this;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getErrorMessage() {return errorMessage;}public void setErrorMessage(String errorMessage) {this.errorMessage = errorMessage;}public T getData() {return data;}public void setData(T data) {this.data = data;}public String getHost() {return host;}public void setHost(String host) {this.host = host;}public static void main(String[] args) {//前置/*AppHttpCodeEnum success = AppHttpCodeEnum.SUCCESS;System.out.println(success.getCode());System.out.println(success.getErrorMessage());*///查询一个对象/*Map map = new HashMap();map.put("name","zhangsan");map.put("age",18);ResponseResult result = ResponseResult.okResult(map);System.out.println(JSON.toJSONString(result));*///新增,修改,删除 在项目中统一返回成功即可/* ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.SUCCESS);System.out.println(JSON.toJSONString(result));*///根据不用的业务返回不同的提示信息 比如:当前操作需要登录、参数错误/*ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);System.out.println(JSON.toJSONString(result));*///查询分页信息
// PageResponseResult responseResult = new PageResponseResult(1,5,50);
// List list = new ArrayList();
// list.add("itcast");
// list.add("itheima");
// responseResult.setData(list);
// System.out.println(JSON.toJSONString(responseResult));}}
这里的逻辑相对来说不是很难理解
这里忘记了,引入项目的时候导入过了
(3)mapper层
mapper层更简单了,就直接继承下BaseMapper就行了
(4)接口测试工具
我这里用习惯了apifox所以就还是用apifox就行测试了,如果想用其他的可以去了解下knife4j
四、网关
不了解网关的可以看下这篇文章,简而言之就是一对多,是微服务中必不可少的
重生之我在暑假学习微服务第十天《网关篇》
1、创建heima-leadnews-app-gateway
引入依赖,在父工程下引入即可,一定要看好位置
<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、改造模块
(1)实体类
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);}
}
(2)bootstrap.yml配置文件
这里别忘了换ip地址
server:port: 51601
spring:application:name: leadnews-app-gatewaycloud:nacos:discovery:server-addr: 192.168.73.134:8848config:server-addr: 192.168.73.134:8848file-extension: yml
(3)nacos配置
这里直接复制过去就行
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
(4)配置过滤器
这里的主要功能就是进行过滤的,整体逻辑也不复杂
package com.heima.app.gateway.filter;import com.alibaba.cloud.commons.lang.StringUtils;
import com.heima.app.gateway.util.AppJwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
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获取对象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)){//token不存在response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}//5.判断token是否正确try {Claims claimsBoby = AppJwtUtil.getClaimsBody(token);if (AppJwtUtil.verifyToken(claimsBoby) == 1 || AppJwtUtil.verifyToken(claimsBoby) == 2) {//token错误response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}} catch (Exception e) {e.printStackTrace();//token错误response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}//6.放行return chain.filter(exchange);}@Overridepublic int getOrder() {return 0;}
}
3、部署前端项目
主要工作就是对nginx的改造
(1)创建存放conf的目录
因为项目所涉及不同的网关,所以要放在文件夹下统一保存
(2)创建APP端conf
(3)改造conf文件
将所画的改为自己的信息即可
这是我的文件内容
upstream heima-app-gateway{server localhost:51601;
}server {listen 8801;location / {root D:\AllCode\java_Code\springcloud\qianduan_All\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; #记录代理信息}
}
(4)改造原本的conf文件
这里记得修改为自己的路径,不过如果放在一个文件夹下其实不用更改
直接cv即可
#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;
}
4、测试
准备工作完成开始测试
介绍下网关发挥的作用,可以看到这里可以通过网关的端口来访问登录功能
前后端联调测试
访问:http://localhost:8801/
测试登录功能
进入这个页面就测试成功了
结语
本文记录了从黑马商城项目转向黑马头条项目的过程。文章详细介绍了项目技术栈(包括SpringCloud、Nacos、Kafka等)、环境配置、模块改造(用户服务、网关服务)的具体步骤,并重点讲解了登录功能的实现和网关过滤器的配置。还分享了前后端联调测试经验,展示了如何通过Nginx配置实现前后端对接。该项目采用微服务架构,包含用户中心、自媒体等多个微服务模块,通过SpringCloudGateway实现统一API路由和权限控制。文章为开发者提供了完整的项目搭建指南和技术实现细节。