如果你追求一个局部的更好甚至完美,你有可能花费巨大的资源和时间;
从总体上看,这往往意味着总体的浪费和失败,这是传说中的“打赢了战役打输了战争”。
系列文章目录
- 项目搭建
- App登录及网关
文章目录
- 系列文章目录
- 一、App登录
- 1. 需求分析
- 2. 表结构分析
- ⑴. 导入数据库
- ⑵. 库表
- ⑶. 用户表(登录)
- ⑷. 实体类
- 3. 手动加密(md5+随机字符串)
- 4. 运营端微服务搭建
- ⑴. 创建模块
- ⑵. 引导类
- ⑶. 微服务配置文件
- ⑷. 日志配置文件
- ⑸. Nacos配置文件
- ⑹. 微服务标准包结构
- 5. 接口定义
- ⑴. 接口返回类分析
- ①. HttpCode枚举
- ②. 通用的结果返回类
- ③. 上面的返回类测试
- ④. 分页返回类
- ⑵. 实体类
- ⑶. Controller
- ⑷. Mapper
- ⑸. service
- ⑹. 实现类Impl
- ⑺. Controller
- 二、接口测试工具
- 1. Postman
- 2. Swagger
- ⑴. 配置
- ①. 引入依赖
- ②. 配置类
- ③. 自动配置
- ⑵. 注解
- ①. 常用注解
- ②. 接口注解
- ③. 参数注解
- ④. 在线API文档
- 3. Knife4j
- ⑴. 配置
- ①. 引入依赖
- ②. 配置类
- ③. 自动配置
- ⑵. 文档(可下载离线文档)
- 三、App网关
- 1. gateway网关微服务
- ⑴. 服务工程结构
- ⑵. 配置
- ①. 导入依赖
- ②. 引导类
- ③. 配置文件
- ④. nacos配置
- ⑶. 测试
- 2. 认证过滤器
- ⑴. 思路分析
- ⑵. 全局过滤器
- ⑶. 断点调试
- 四、App前端项目集成
- 1. nginx包
- 2. 前端项目
- 3. 配置nginx.conf文件1
- 4. 配置nginx.conf文件2
- 5. 重新加载nginx
- 6. 运行测试
一、App登录
1. 需求分析
- 登录: 登录后的用户权限较大,可以查看,也可以操作(点赞,关注,评论)
- 不登录,先看看: 游客只有查看的权限
2. 表结构分析
⑴. 导入数据库
sql文件链接:https://pan.baidu.com/s/11ITsQZQkR0Yl20lT10omwQ?pwd=abcd
⑵. 库表
关于app端用户相关的内容较多,可以单独设置一个库leadnews_user
表名称 | 说明 |
---|---|
ap_user | APP用户信息表 |
ap_user_fan | APP用户粉丝信息表 |
ap_user_follow | APP用户关注信息表 |
ap_user_realname | APP实名认证信息表 |
⑶. 用户表(登录)
登录需要用到的是 ap_user
表,表结构如下:
DDL文件:
CREATE TABLE `ap_user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`salt` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密码、通信等加密盐',
`name` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户名',
`password` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密码,md5加密',
`phone` varchar(11) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '手机号',
`image` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '头像',
`sex` tinyint(1) unsigned DEFAULT NULL COMMENT '0 男\r\n 1 女\r\n 2 未知',
`is_certification` tinyint(1) unsigned DEFAULT NULL COMMENT '0 未\r\n 1 是',
`is_identity_authentication` tinyint(1) DEFAULT NULL COMMENT '是否身份认证',
`status` tinyint(1) unsigned DEFAULT NULL COMMENT '0正常\r\n 1锁定',
`flag` tinyint(1) unsigned DEFAULT NULL COMMENT '0 普通用户\r\n 1 自媒体人\r\n 2 大V',
`created_time` datetime DEFAULT NULL COMMENT '注册时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='APP用户信息表';
tinyint类型: 占1个字节,不指定unsigned(非负数),值范围(-128,127),指定了unsigned,值范围(0,255)
tinyint 通常表示小范围的数值,或者表示true或false,通常值为0表示false,值为1表示true
⑷. 实体类
新建 src/main/java/com/heima/model/user/pojos/ApUser.java
文件(app_user表对应的实体类):
/**
* <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. 手动加密(md5+随机字符串)
md5是不可逆加密,md5相同的密码每次加密都一样,不太安全。在md5的基础上手动加盐(salt)处理
注册(生成盐)
登录(使用盐来配合验证)
4. 运营端微服务搭建
⑴. 创建模块
⑵. 引导类
新建 src/main/java/com/heima/user/UserApplication.java
文件:
@SpringBootApplication
@EnableDiscoveryClient // 集成当前的注册中心
@MapperScan("com.heima.user.mapper") // 集成myBatisPlus 扫描mapper
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class,args);
}
}
⑶. 微服务配置文件
新建 heima-leadnews-service/heima-leadnews-user/src/main/resources/bootstrap.yml
文件:
server:
port: 51801
spring:
application:
name: leadnews-user
cloud:
nacos:
discovery:
server-addr: 192.168.200.130:8848
config:
server-addr: 192.168.200.130:8848
file-extension: yml
⑷. 日志配置文件
新建 heima-leadnews-service/heima-leadnews-user/src/main/resources/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>
⑸. Nacos配置文件
spring:
redis:
host: 192.168.200.130
password: leadnews
port: 6379
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/leadnews_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
username: root
password: 123456
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
# 设置别名包扫描路径,通过该属性可以给包中的类注册别名
type-aliases-package: com.heima.model.user.pojos
⑹. 微服务标准包结构
5. 接口定义
⑴. 接口返回类分析
①. HttpCode枚举
查看 com/heima/model/common/enums/AppHttpCodeEnum.java
文件:
public enum AppHttpCodeEnum {
// 成功段固定为200
SUCCESS(200,"操作成功"),
// 登录段1~50
NEED_LOGIN(1,"需要登录后操作"),
LOGIN_PASSWORD_ERROR(2,"密码错误"),
// TOKEN50~100
TOKEN_INVALID(50,"无效的TOKEN"),
TOKEN_EXPIRE(51,"TOKEN已过期"),
TOKEN_REQUIRE(52,"TOKEN是必须的"),
// SIGN验签 100~120
SIGN_INVALID(100,"无效的SIGN"),
SIG_TIMEOUT(101,"SIGN已过期"),
// 参数错误 500~1000
PARAM_REQUIRE(500,"缺少参数"),
PARAM_INVALID(501,"无效参数"),
PARAM_IMAGE_FORMAT_ERROR(502,"图片格式有误"),
SERVER_ERROR(503,"服务器内部错误"),
// 数据错误 1000~2000
DATA_EXIST(1000,"数据已经存在"),
AP_USER_DATA_NOT_EXIST(1001,"ApUser数据不存在"),
DATA_NOT_EXIST(1002,"数据不存在"),
// 数据错误 3000~3500
NO_OPERATOR_AUTH(3000,"无权限操作"),
NEED_ADMIND(3001,"需要管理员权限");
int code;
String errorMessage;
AppHttpCodeEnum(int code, String errorMessage){
this.code = code;
this.errorMessage = errorMessage;
}
public int getCode() {
return code;
}
public String getErrorMessage() {
return errorMessage;
}
}
②. 通用的结果返回类
查看 com/heima/model/common/dtos/PageResponseResult.java
文件:
/**
* 通用的结果返回类
* @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.okResult(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));
}
}
③. 上面的返回类测试
④. 分页返回类
查看 com/heima/model/common/dtos/PageResponseResult.java
文件:
public class PageResponseResult extends ResponseResult implements Serializable {
private Integer currentPage;
private Integer size;
private Integer total;
public PageResponseResult(Integer currentPage, Integer size, Integer total) {
this.currentPage = currentPage;
this.size = size;
this.total = total;
}
public PageResponseResult() {
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
}
⑵. 实体类
新建 heima-leadnews-model/src/main/java/com/heima/model/user/dtos/LoginDto.java
文件:
@Data
public class LoginDto {
/**
* 手机号
*/
@ApiModelProperty(value = "手机号",required = true)
private String phone;
/**
* 密码
*/
@ApiModelProperty(value = "密码",required = true)
private String password;
}
⑶. Controller
新建 heima-leadnews-service/heima-leadnews-user/src/main/java/com/heima/user/controller/v1/ApUserLoginController.java
文件:
@RestController
@RequestMapping("/api/v1/login")
public class ApUserLoginController {
@PostMapping("/login_auth")
public ResponseResult login(@RequestBody LoginDto dto) {
return null;
}
}
⑷. Mapper
新建 heima-leadnews-service/heima-leadnews-user/src/main/java/com/heima/user/mapper/ApUserMapper.java
文件:
@Mapper
public interface ApUserMapper extends BaseMapper<ApUser> {
}
⑸. service
新建 heima-leadnews-service/heima-leadnews-user/src/main/java/com/heima/user/service/ApUserService.java
文件:
public interface ApUserService extends IService<ApUser>{
/**
* app端登录
* @param dto
* @return
*/
public ResponseResult login(LoginDto dto);
}
⑹. 实现类Impl
- 用户输入了用户名和密码进行登录,校验成功后返回jwt(基于当前用户的id生成)
- 用户游客登录,生成jwt返回(基于默认值0生成)
新建 heima-leadnews-service/heima-leadnews-user/src/main/java/com/heima/user/service/impl/ApUserServiceImpl.java
文件:
@Service
public class ApUserServiceImpl extends ServiceImpl<ApUserMapper, ApUser> implements ApUserService {
@Override
public ResponseResult login(LoginDto dto) {
//1.正常登录(手机号+密码登录)
if (!StringUtils.isBlank(dto.getPhone()) && !StringUtils.isBlank(dto.getPassword())) {
//1.1查询用户
ApUser apUser = getOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, dto.getPhone()));
if (apUser == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"用户不存在");
}
//1.2 比对密码
String salt = apUser.getSalt();
String pswd = dto.getPassword();
pswd = DigestUtils.md5DigestAsHex((pswd + salt).getBytes());
if (!pswd.equals(apUser.getPassword())) {
return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
}
//1.3 返回数据 jwt
Map<String, Object> map = new HashMap<>();
map.put("token", AppJwtUtil.getToken(apUser.getId().longValue()));
apUser.setSalt("");
apUser.setPassword("");
map.put("user", apUser);
return ResponseResult.okResult(map);
} else {
//2.游客 同样返回token id = 0
Map<String, Object> map = new HashMap<>();
map.put("token", AppJwtUtil.getToken(0l));
return ResponseResult.okResult(map);
}
}
}
⑺. Controller
编辑 heima-leadnews-service/heima-leadnews-user/src/main/java/com/heima/user/controller/v1/ApUserLoginController.java
文件:
@RestController
@RequestMapping("/api/v1/login")
@Api(value = "app端用户登录",tags = "app端用户登录")
public class ApUserLoginController {
@Autowired
private ApUserService apUserService;
@PostMapping("/login_auth")
@ApiOperation("用户登录")
public ResponseResult login(@RequestBody LoginDto dto){
return apUserService.login(dto);
}
}
二、接口测试工具
1. Postman
测试 账号错误
、密码错误
、游客登录
、用户登录
返回信息是否正确
2. Swagger
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务(https://swagger.io/)。
⑴. 配置
①. 引入依赖
在 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/src/main/java/com/heima/common/swagger/SwaggerConfiguration.java
文件:
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
@Bean
public 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/src/main/resources/META-INF/spring.factories
文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.heima.common.exception.ExceptionCatch,\
com.heima.common.swagger.SwaggerConfiguration
⑵. 注解
①. 常用注解
在Java类中添加Swagger的注解即可生成Swagger接口文档,常用Swagger注解如下:
- @Api:修饰整个类,描述Controller的作用
- @ApiOperation:描述一个类的一个方法,或者说一个接口
- @ApiParam:单个参数的描述信息
- @ApiModel:用对象来接收参数
- @ApiModelProperty:用对象接收参数时,描述对象的一个字段
- @ApiResponse:HTTP响应其中1个描述
- @ApiResponses:HTTP响应整体描述
- @ApiIgnore:使用该注解忽略这个API
- @ApiError :发生错误返回的信息
- @ApiImplicitParam:一个请求参数
- @ApiImplicitParams:多个请求参数的描述信息
@ApiImplicitParam属性:
属性 | 取值 | 作用 |
---|---|---|
paramType | 查询参数类型 | |
path | 以地址的形式提交数据 | |
query | 直接跟参数完成自动映射赋值 | |
body | 以流的形式提交 仅支持POST | |
header | 参数在request headers 里边提交 | |
form | 以form表单的形式提交 仅支持POST | |
dataType | 参数的数据类型 只作为标志说明,并没有实际验证 | |
Long | ||
String | ||
name | 接收参数名 | |
value | 接收参数的意义描述 | |
required | 参数是否必填 | |
true | 必填 | |
false | 非必填 | |
defaultValue | 默认值 |
②. 接口注解
编辑 heima-leadnews-service/heima-leadnews-user/src/main/java/com/heima/user/controller/v1/ApUserLoginController.java
文件:
@RestController
@RequestMapping("/api/v1/login")
@Api(value = "app端用户登录", tags = "ap_user", description = "app端用户登录API")
public class ApUserLoginController {
@Autowired
private ApUserService apUserService;
@PostMapping("/login_auth")
@ApiOperation("用户登录")
public ResponseResult login(@RequestBody LoginDto dto){
return apUserService.login(dto);
}
}
③. 参数注解
编辑 heima-leadnews-model/src/main/java/com/heima/model/user/dtos/LoginDto.java
文件:
@Data
public class LoginDto {
/**
* 手机号
*/
@ApiModelProperty(value="手机号",required = true)
private String phone;
/**
* 密码
*/
@ApiModelProperty(value="密码",required = true)
private String password;
}
④. 在线API文档
启动user微服务,访问地址:http://localhost:51801/swagger-ui.html
3. Knife4j
knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui,取名kni4j是希望它能像一把匕首一样小巧,轻量,并且功能强悍!(https://doc.xiaominfo.com/)
⑴. 配置
①. 引入依赖
编辑 heima-leadnews-common/pom.xml
文件:
<!--knife4j接口文档-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
②. 配置类
新建 heima-leadnews-common/src/main/java/com/heima/common/swagger/Swagger2Configuration.java
文件:
@Configuration
@EnableSwagger2
@EnableKnife4j
@Import(BeanValidatorPluginsConfiguration.class)
public class Swagger2Configuration {
@Bean(value = "defaultApi2")
public Docket defaultApi2() {
Docket docket=new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
//分组名称
.groupName("1.0")
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.heima"))
.paths(PathSelectors.any())
.build();
return docket;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("新闻头条API文档")
.description("新闻头条API文档")
.version("1.0")
.build();
}
}
以上有两个注解需要特别说明:
注解 | 说明 |
---|---|
@EnableSwagger2 | 该注解是Springfox-swagger框架提供的使用Swagger注解,该注解必须加 |
@EnableKnife4j | 该注解是knife4j 提供的增强注解,Ui提供了例如动态参数、参数过滤、接口排序等增强功能,如果你想使用这些增强功能就必须加该注解,否则可以不用加 |
③. 自动配置
编辑 heima-leadnews-common/src/main/resources/META-INF/spring.factories
文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.heima.common.exception.ExceptionCatch,\
com.heima.common.swagger.SwaggerConfiguration,\
com.heima.common.swagger.Swagger2Configuration
⑵. 文档(可下载离线文档)
接口文档: http://localhost:51801/doc.htm
三、App网关
1. gateway网关微服务
⑴. 服务工程结构
- heima-leadnews-gateway 网关
- heima-leadnews-admin-gateway 管理平台
- heima-leadnews-wemedia-gateway 用户自媒体平台
- heima-leadnews-app-gateway 用户移动APP
⑵. 配置
①. 导入依赖
新建 heima-leadnews-gateway/pom.xml
文件:
<dependencies>
<!--gateway的staeter-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos的注册中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--nacos的配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--jwt解析jar包-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
</dependencies>
②. 引导类
新建 heima-leadnews-gateway/heima-leadnews-app-gateway/src/main/java/com/heima/app/gateway/AppGatewayApplication.java
文件:
@SpringBootApplication
@EnableDiscoveryClient //开启注册中心
public class AppGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(AppGatewayApplication.class,args);
}
}
③. 配置文件
编辑 heima-leadnews-gateway/heima-leadnews-app-gateway/src/main/resources/bootstrap.yml
文件:
server:
port: 51601
spring:
application:
name: leadnews-app-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.200.130:8848
config:
server-addr: 192.168.200.130:8848
file-extension: yml
④. nacos配置
nocos地址: http://192.168.200.130:8848/nacos
spring:
cloud:
gateway:
globalcors:
add-to-simple-url-handler-mapping: true
corsConfigurations:
'[/**]':
allowedHeaders: "*"
allowedOrigins: "*"
allowedMethods:
- GET
- POST
- DELETE
- PUT
- OPTION
routes:
# 平台管理
- id: user
uri: lb://leadnews-user
predicates:
- Path=/user/**
filters:
- StripPrefix= 1
⑶. 测试
启动项目网关和用户两个服务,使用postman进行测试
网关后的请求地址: localhost:51601/user/api/v1/login/login_auth
2. 认证过滤器
⑴. 思路分析
- 用户进入网关开始登陆,网关过滤器进行判断,如果是登录,则路由到后台管理微服务进行登录
- 用户登录成功,后台管理微服务签发JWT TOKEN信息返回给用户
- 用户再次进入网关开始访问,网关过滤器接收用户携带的TOKEN
- 网关过滤器解析TOKEN ,判断是否有权限,如果有,则放行,如果没有则返回未认证错误
⑵. 全局过滤器
新建 heima-leadnews-gateway/heima-leadnews-app-gateway/src/main/java/com/heima/app/gateway/filter/AuthorizeFilter.java
文件:
@Component
@Slf4j
public class AuthorizeFilter implements Ordered, GlobalFilter {
@Override
public 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.获取token
String 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
*/
@Override
public int getOrder() {
return 0;
}
}
⑶. 断点调试
启动user服务,访问其他微服务,会提示需要认证才能访问,这个时候需要在heads中设置设置token才能正常访问。
四、App前端项目集成
- 通过nginx的反向代理功能访问后台的网关资源
- 通过nginx的静态服务器功能访问前端静态页面
1. nginx包
资源链接: https://pan.baidu.com/s/1gPfoG0FnLC3dIUjJhqlKSQ?pwd=abcd
解压包,运行nginx
2. 前端项目
资源链接: https://pan.baidu.com/s/1wqfxtQCj_aGqSZVxgADVTQ?pwd=abcd
解压包,记住前端项目存放路径
3. 配置nginx.conf文件1
(nginx包中)新建 D:\code\hm\leadnews\config\nginx-1.18.0\conf\leadnews.conf\heima-leadnews-app.conf
文件:
upstream heima-app-gateway{
server localhost:51601; # 根据网关去做的请求
}
server {
listen 8801;
location / {
root D:/code/hm/leadnews/config/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; # 记录真实发出请求的客户端IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #记录代理信息
}
}
4. 配置nginx.conf文件2
(nginx包中)编辑 D:\code\hm\leadnews\config\nginx-1.18.0\conf\leadnews.conf\nginx.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;
}
5. 重新加载nginx
# 重新加载nginx
nginx -s reload
6. 运行测试
前端地址: http://localhost:8801/