黑马头条项目[修改版]-第三天
0.黑马头条-学习目标
- 能够完成网关统一鉴权的功能
- 能够完成认证用户列表查询
- 能够熟悉app端用户认证审核流程
- 能够完成app用户审核代码开发
1.网关功能回顾
1.1.微服务网关概述
不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:
- 客户端会多次请求不同的微服务,增加了客户端的复杂性
- 存在跨域请求,在一定场景下处理相对复杂
- 认证复杂,每个服务都需要独立认证
- 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施
- 某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难
以上这些问题可以借助网关解决。
网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 网关来做,这样既提高业务灵活性又不缺安全性,典型的架构图如图所示:
优点如下:
- 安全 ,只有网关系统对外进行暴露,微服务可以隐藏在内网,通过防火墙保护。
- 易于监控。可以在网关收集监控数据并将其推送到外部系统进行分析。
- 易于认证。可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
- 减少了客户端与各个微服务之间的交互次数
- 易于统一授权。
总结:微服务网关就是一个系统,通过暴露该微服务网关系统,方便我们进行相关的鉴权,安全控制,日志统一处理,易于监控的相关功能。
实现微服务网关的技术有很多,
- nginx Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务
- zuul ,Zuul 是 Netflix 出品的一个基于 JVM 路由和服务端的负载均衡器。
- spring-cloud-gateway, 是spring 出品的 基于spring 的网关项目,集成断路器,路径重写,性能比Zuul好。
我们使用gateway这个网关技术,无缝衔接到基于spring cloud的微服务开发中来。
gateway官网:
https://spring.io/projects/spring-cloud-gateway
1.2.搭建gateway网关微服务
1.创建heima-leadnews-admin-gateway微服务
pom.xml文件
<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>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
</dependencies>
引导类
@SpringBootApplication
@EnableDiscoveryClient
public class AdminGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(AdminGatewayApplication.class,args);
}
}
application.yml
server:
port: 6001
spring:
application:
name: leadnews-user-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.200.130:8848
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有请求
allowedOrigins: "*" #跨域处理 允许所有的域
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
routes:
# 平台管理
- id: admin
uri: lb://leadnews-admin
predicates:
- Path=/admin/** #http://localhost:6001/admin/api/v1/channel/list -->http://localhost:9001/api/v1/channel/list
filters:
- StripPrefix= 1
2.启动测试,查看nacos中是否有gateway的注册信息,使用postman测试
2.网关校验JWT
2.1.全局过滤器实现jwt校验
思路分析:
- 用户进入网关开始登陆,网关过滤器进行判断,如果是登录,则路由到后台管理微服务进行登录
- 用户登录成功,后台管理微服务签发JWT TOKEN信息返回给用户
- 用户再次进入网关开始访问,网关过滤器接收用户携带的TOKEN
- 网关过滤器解析TOKEN ,判断是否有权限,如果有,则放行,如果没有则返回未认证错误
2.2.网关服务新建全局过滤器
1.将heima-leadnews-utils模块中的AppJwtUtil类拷贝到heima-leadnews-admin-gateway网关模块下
2.在heima-leadnews-admin-gateway网关模块编写全局过滤器。
@Component
@Log4j2
public class AuthorizeFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1.获取请求对象和响应对象
//2.判断当前的请求是否为登录,如果是,直接放行
//3.获取当前用户的请求头jwt信息
//4.判断当前令牌是否存在
//5.如果令牌存在,解析jwt令牌,判断该令牌是否合法,如果不合法,则向客户端返回错误信息
//5.1 合法,则向header中重新设置userId
//6.放行
return null;
}
/**
* 优先级设置
* 值越小,优先级越高
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
3.具体代码编写
@Component
@Log4j2
public class AuthorizeFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1.获取请求对象和响应对象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//2.判断当前的请求是否为登录,如果是,直接放行
if(request.getURI().getPath().contains("/login/in")){
//放行
return chain.filter(exchange);
}
//3.获取当前用户的请求头jwt信息
HttpHeaders headers = request.getHeaders();
String jwtToken = headers.getFirst("token");
//4.判断当前令牌是否存在
if(StringUtils.isEmpty(jwtToken)){
//如果不存在,向客户端返回错误提示信息
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
try {
//5.如果令牌存在,解析jwt令牌,判断该令牌是否合法,如果不合法,则向客户端返回错误信息
Claims claims = AppJwtUtil.getClaimsBody(jwtToken);
int result = AppJwtUtil.verifyToken(claims);
if(result == 0 || result == -1){
//5.1 合法,则向header中重新设置userId
Integer id = (Integer) claims.get("id");
log.info("find userid:{} from uri:{}",id,request.getURI());
//重新设置token到header中
ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {
httpHeaders.add("userId", id + "");
}).build();
exchange.mutate().request(serverHttpRequest).build();
}
}catch (Exception e){
e.printStackTrace();
//想客户端返回错误提示信息
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
//6.放行
return chain.filter(exchange);
}
/**
* 优先级设置
* 值越小,优先级越高
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
4.重启测试
先登录
启动admin服务,继续访问其他微服务,会提示需要认证才能访问,这个时候需要在heads中设置设置token才能正常访问。
3.app端用户认证列表查询
3.1.需求分析及环境搭建
需求分析
用户需要先在前台进行认证信息的提交
用户实名认证之后,需要到后台查询出用户认证列表,进行审核
下面先来实现用户认证列表查询操作。
当用户在app前端进行了认证请求会自动往ap_user_realname表中加入数据,目前所查询的就是用户认证列表。
默认查询待审核的信息,也可以根据状态进行过滤。
leadnews_user数据库中,用户认证表:ap_user_realname
环境搭建
1.在heima-leadnews-model中创建ApUserRealname实体类
/**
* <p>
* APP实名认证信息表
* </p>
*
* @author itheima
*/
@Data
@TableName("ap_user_realname")
public class ApUserRealname implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 账号ID
*/
@TableField("user_id")
private Integer userId;
/**
* 用户名称
*/
@TableField("name")
private String name;
/**
* 资源名称
*/
@TableField("idno")
private String idno;
/**
* 正面照片
*/
@TableField("font_image")
private String fontImage;
/**
* 背面照片
*/
@TableField("back_image")
private String backImage;
/**
* 手持照片
*/
@TableField("hold_image")
private String holdImage;
/**
* 活体照片
*/
@TableField("live_image")
private String liveImage;
/**
* 状态
0 创建中
1 待审核
2 审核失败
9 审核通过
*/
@TableField("status")
private Short status;
/**
* 拒绝原因
*/
@TableField("reason")
private String reason;
/**
* 创建时间
*/
@TableField("created_time")
private Date createdTime;
/**
* 提交时间
*/
@TableField("submited_time")
private Date submitedTime;
/**
* 更新时间
*/
@TableField("updated_time")
private Date updatedTime;
}
2.新建heima-leadnews-user微服务项目,pom.xml引入依赖,配置application.yml和logback.xml文件,创建引导类
pom.xml
<dependencies>
<!-- 引入依赖模块 -->
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-model</artifactId>
</dependency>
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-common</artifactId>
</dependency>
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-apis</artifactId>
</dependency>
<!-- Spring boot starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 9002
spring:
application:
name: leadnews-user
cloud:
nacos:
discovery:
server-addr: 192.168.200.130:8848
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/leadnews_user?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 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>
引导类
@SpringBootApplication
@MapperScan("com.heima.user.mapper")
@EnableDiscoveryClient
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class,args);
}
/**
* mybatis-plus分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
3.2.功能实现
1.在heima-leadnews-apis模块中新增接口:com.heima.api.user.ApUserRealnameControllerApi
public interface ApUserRealnameControllerApi {
/**
* 按照状态分页查询用户列表
* @param dto
* @return
*/
public ResponseResult loadListByStatus(AuthDto dto);
}
2.在heima-leadnews-model中创建AuthDto
@Data
public class AuthDto extends PageRequestDto {
/**
* 状态
*/
private Short status;
}
3.在heima-leadnews-user中创建ApUserRealnameMapper
@Mapper
public interface ApUserRealnameMapper extends BaseMapper<ApUserRealname> {
}
4.在heima-leadnews-user中创建ApUserRealnameService
public interface ApUserRealnameService extends IService<ApUserRealname> {
/**
* 按照状态分页查询用户列表
* @param dto
* @return
*/
public ResponseResult loadListByStatus(AuthDto dto);
}
5.在heima-leadnews-user中创建ApUserRealnameServiceImpl
@Service
public class ApUserRealnameServiceImpl extends ServiceImpl<ApUserRealnameMapper, ApUserRealname> implements ApUserRealnameService {
@Override
public ResponseResult loadListByStatus(AuthDto dto) {
//1.检查参数
if(dto == null ){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//分页检查
dto.checkParam();
//2.根据状态分页查询
LambdaQueryWrapper<ApUserRealname> lambdaQueryWrapper = new LambdaQueryWrapper();
if(dto.getStatus() != null){
lambdaQueryWrapper.eq(ApUserRealname::getStatus,dto.getStatus());
}
//分页条件构建
IPage pageParam = new Page(dto.getPage(),dto.getSize());
IPage page = page(pageParam, lambdaQueryWrapper);
//3.返回结果
PageResponseResult responseResult = new PageResponseResult(dto.getPage(),dto.getSize(),(int)page.getTotal());
responseResult.setData(page.getRecords());
return responseResult;
}
}
6.在heima-leadnews-user中创建ApUserRealnameController
@RestController
@RequestMapping("/api/v1/auth")
public class ApUserRealnameController implements ApUserRealnameControllerApi {
@Autowired
private ApUserRealnameService apUserRealnameService;
@PostMapping("/list")
@Override
public ResponseResult loadListByStatus(@RequestBody AuthDto dto) {
return apUserRealnameService.loadListByStatus(dto);
}
}
7.在heima-leadnews-user中创建ExceptionCatchConfig和SwaggerConfiguration
@Configuration
@ComponentScan("com.heima.common.exception")
public class ExceptionCatchConfig {
}
@Configuration
@EnableSwagger2
@EnableKnife4j
@Import(BeanValidatorPluginsConfiguration.class)
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();
}
}
4.app端用户认证后审核
4.1.需求分析
- 在app端的个人中心用户可以实名认证,需要材料为:姓名、身份证号、身份证正面照、身份证反面照、手持照片、活体照片(通过微笑、眨眼、张嘴、摇头、点头等组合动作,确保操作的为真实活体人脸。),当用户提交审核后就到了后端让运营管理人员进行审核
- 平台运营端查看用户认证信息,进行审核,其中审核包括了用户身份审核,需要对接公安系统校验身份证信息
- 用户通过审核后需要开通自媒体账号(该账号的用户名和密码与app一致)
- 用户通过审核后需要在article中在作者表中新建一个作者信息
4.2.自媒体微服务构建
4.2.1.自媒体工程搭建及接口分析
1.新建heima-leadnews-wemedia模块,pom.xml引入依赖,application.yml,引导类
pom.xml
<dependencies>
<!-- 引入依赖模块 -->
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-model</artifactId>
</dependency>
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-common</artifactId>
</dependency>
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-apis</artifactId>
</dependency>
<!-- Spring boot starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 9004
spring:
application:
name: leadnews-wemedia
cloud:
nacos:
discovery:
server-addr: 192.168.200.130:8848
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/leadnews_wemedia?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: root
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
# 设置别名包扫描路径,通过该属性可以给包中的类注册别名
type-aliases-package: com.heima.model.media.pojos
引导类
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.wemedia.mapper")
public class WemediaApplication {
public static void main(String[] args) {
SpringApplication.run(WemediaApplication.class,args);
}
/**
* mybatis-plus分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
2.在heima-leadnews-wemedia中创建ExceptionCatchConfig和SwaggerConfiguration
@Configuration
@ComponentScan("com.heima.common.exception")
public class ExceptionCatchConfig {
}
@Configuration
@EnableSwagger2
@EnableKnife4j
@Import(BeanValidatorPluginsConfiguration.class)
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();
}
}
3.表分析及实体类构建
leadnews_wemedia数据库中,自媒体用户表:wm_user
在heima-leadnews-model中创建WmUser
/**
* <p>
* 自媒体用户信息表
* </p>
*
* @author itheima
*/
@Data
@TableName("wm_user")
public class WmUser implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@TableField("ap_user_id")
private Integer apUserId;
@TableField("ap_author_id")
private Integer apAuthorId;
/**
* 登录用户名
*/
@TableField("name")
private String name;
/**
* 登录密码
*/
@TableField("password")
private String password;
/**
* 盐
*/
@TableField("salt")
private String salt;
/**
* 昵称
*/
@TableField("nickname")
private String nickname;
/**
* 头像
*/
@TableField("image")
private String image;
/**
* 归属地
*/
@TableField("location")
private String location;
/**
* 手机号
*/
@TableField("phone")
private String phone;
/**
* 状态
0 暂时不可用
1 永久不可用
9 正常可用
*/
@TableField("status")
private Integer status;
/**
* 邮箱
*/
@TableField("email")
private String email;
/**
* 账号类型
0 个人
1 企业
2 子账号
*/
@TableField("type")
private Integer type;
/**
* 运营评分
*/
@TableField("score")
private Integer score;
/**
* 最后一次登录时间
*/
@TableField("login_time")
private Date loginTime;
/**
* 创建时间
*/
@TableField("created_time")
private Date createdTime;
}
4.在heima-leadnews-apis中新建接口:com.heima.api.wemedia.WmUserControllerApi
public interface WmUserControllerApi {
/**
* 保存自媒体用户
* @param wmUser
* @return
*/
public ResponseResult save(WmUser wmUser);
/**
* 根据名称查询自媒体用户
* @param name
* @return
*/
public WmUser findByName(String name);
}
4.2.3.自媒体接口实现
1.在heima-leadnews-wemedia中创建WmUserMapper
@Mapper
public interface WmUserMapper extends BaseMapper<WmUser> {
}
2.在heima-leadnews-wemedia中创建WmUserService
public interface WmUserService extends IService<WmUser> {
}
3.在heima-leadnews-wemedia中创建WmUserServiceImpl
@Service
public class WmUserServiceImpl extends ServiceImpl<WmUserMapper, WmUser> implements WmUserService {
}
4.在heima-leadnews-wemedia中创建WmUserController
@RestController
@RequestMapping("/api/v1/user")
public class WmUserController implements WmUserControllerApi {
@Autowired
private WmUserService wmUserService;
/**
* 增加用户
* @param wmUser
* @return
*/
@PostMapping("/save")
@Override
public ResponseResult save(@RequestBody WmUser wmUser) {
wmUserService.save(wmUser);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
/**
* 根据用户名查询用户信息
* @param name
* @return
*/
@GetMapping("/findByName/{name}")
@Override
public WmUser findByName(@PathVariable("name") String name) {
List<WmUser> list = wmUserService.list(Wrappers.<WmUser>lambdaQuery().eq(WmUser::getName, name));
if(list != null && !list.isEmpty()){ //isEmpty() : 本质是判断list.size() == 0
return list.get(0);
}
return null;
}
}
5.启动项目,在postman中测试
根据用户名查询用户信息测试
增加用户测试
4.3.文章微服务构建
4.3.1.article微服务创建
1.新建模块heima-leadnews-article,pom.xml引入依赖,application.yml,引导类。
pom.xml
<dependencies>
<!-- 引入依赖模块 -->
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-model</artifactId>
</dependency>
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-common</artifactId>
</dependency>
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-apis</artifactId>
</dependency>
<!-- Spring boot starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 9003
spring:
application:
name: leadnews-article
cloud:
nacos:
discovery:
server-addr: 192.168.200.130:8848
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/leadnews_article?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: root
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
# 设置别名包扫描路径,通过该属性可以给包中的类注册别名
type-aliases-package: com.heima.model.article.pojos
引导类
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.article.mapper")
public class ArticleApplication {
public static void main(String[] args) {
SpringApplication.run(ArticleApplication.class,args);
}
/**
* mybatis-plus分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
2.表分析及实体类构建
leadnews_article数据库中, 作者信息表:ap_author
在heima-leadnews-model中创建ApAuthor
/**
* <p>
* APP文章作者信息表
* </p>
*
* @author itheima
*/
@Data
@TableName("ap_author")
public class ApAuthor implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 作者名称
*/
@TableField("name")
private String name;
/**
* 0 爬取数据
1 签约合作商
2 平台自媒体人
*/
@TableField("type")
private Integer type;
/**
* 社交账号ID
*/
@TableField("user_id")
private Integer userId;
/**
* 创建时间
*/
@TableField("created_time")
private Date createdTime;
/**
* 自媒体账号
*/
@TableField("wm_user_id")
private Integer wmUserId;
}
3.在heima-leadnews-apis中新建接口:com.heima.api.article.AuthorControllerApi
public interface AuthorControllerApi {
/**
* 根据用户id查询作者
* @param id
* @return
*/
public ApAuthor findByUserId(Integer id);
/**
* 保存作者
* @param apAuthor
* @return
*/
public ResponseResult save(ApAuthor apAuthor);
}
4.在heima-leadnews-article中创建AuthorMapper
@Mapper
public interface AuthorMapper extends BaseMapper<ApAuthor> {
}
5.在heima-leadnews-article中创建AuthorService
public interface AuthorService extends IService<ApAuthor> {
}
6.在heima-leadnews-article中创建AuthorServiceImpl
@Service
public class AuthorServiceImpl extends ServiceImpl<AuthorMapper, ApAuthor> implements AuthorService {
}
7.在heima-leadnews-article中创建AuthorController
@RestController
@RequestMapping("/api/v1/author")
public class AuthorController implements AuthorControllerApi {
@Autowired
AuthorService authorService;
@GetMapping("/findByUserId/{id}")
@Override
public ApAuthor findByUserId(@PathVariable("id") Integer id) {
List<ApAuthor> list = authorService.list(Wrappers.<ApAuthor>lambdaQuery().eq(ApAuthor::getUserId, id));
if(list != null && !list.isEmpty()){
return list.get(0);
}
return null;
}
@PostMapping("/save")
@Override
public ResponseResult save(@RequestBody ApAuthor apAuthor) {
authorService.save(apAuthor);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
}
8.在heima-leadnews-article中创建ExceptionCatchConfig和SwaggerConfiguration
@Configuration
@ComponentScan("com.heima.common.exception")
public class ExceptionCatchConfig {
}
@Configuration
@EnableSwagger2
@EnableKnife4j
@Import(BeanValidatorPluginsConfiguration.class)
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();
}
}
9.启动项目,使用postman进行测试
增加文章作者
查询文章作者
4.4.用户审核接口定义
1.修改heima-leadnews-apis的com.heima.api.user.ApUserRealnameControllerApi新增方法
public interface ApUserRealnameControllerApi {
....
/**
* 审核通过
* @param dto
* @return
*/
public ResponseResult authPass(AuthDto dto);
/**
* 审核失败
* @param dto
* @return
*/
public ResponseResult authFail(AuthDto dto);
}
在heima-leadnews-user中的ApUserRealnameController中实现方法
@RestController
@RequestMapping("/api/v1/auth")
public class ApUserRealnameController implements ApUserRealnameControllerApi {
........
@PostMapping("/authPass")
@Override
public ResponseResult authPass(@RequestBody AuthDto dto) {
return null;
}
@PostMapping("/authFail")
@Override
public ResponseResult authFail(@RequestBody AuthDto dto) {
return null;
}
}
修改在heima-leadnews-model中的AuthDto
@Data
public class AuthDto extends PageRequestDto {
/**
* 状态
*/
private Short status;
/**
* 认证的id
*/
private Integer id;
}
2.表分析和创建实体类
在新建自媒体账户时需要把apuser信息赋值给自媒体用户
leadnews_user数据库中的,用户信息表:ap_user
在heima-leadnews-model中新增实体类
/**
* <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中创建ApUserMapper
@Mapper
public interface ApUserMapper extends BaseMapper<ApUser> {
}
4.5.User微服务定义feign接口
1.在heima-leadnews-user中的pom.xml文件中引入feign的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.在heima-leadnews-user中的引导类中添加注解@EnableFeignClients
@SpringBootApplication
@MapperScan("com.heima.user.mapper")
@EnableDiscoveryClient
@EnableFeignClients
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class,args);
}
/**
* mybatis-plus分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
3.在heima-leadnews-user中创建feign远程接口
@FeignClient("leadnews-article")
public interface ArticleFeign {
@GetMapping("/api/v1/author/findByUserId/{id}")
public ApAuthor findByUserId(@PathVariable("id") Integer id);
@PostMapping("/api/v1/author/save")
public ResponseResult save(@RequestBody ApAuthor apAuthor);
}
@FeignClient("leadnews-wemedia")
public interface WemediaFeign {
@PostMapping("/api/v1/user/save")
public ResponseResult save(@RequestBody WmUser wmUser);
@GetMapping("/api/v1/user/findByName/{name}")
public WmUser findByName(@PathVariable("name") String name);
}
4.6.用户认证后审核业务实现
1.在heima-leadnews-user的ApUserRealnameService中新增更新用户状态的方法
public interface ApUserRealnameService extends IService<ApUserRealname> {
.....
/**
* 修改认证用户状态
* @param dto
* @param status
* @return
*/
public ResponseResult updateStatusById(AuthDto dto,Short status);
}
2.在heima-leadnews-user的ApUserRealnameServiceImpl中实现方法
/**
* 修改认证用户状态
* @param dto
* @param status
* @return
*/
@Override
public ResponseResult updateStatusById(AuthDto dto, Short status) {
//1.检查参数
if(dto == null || dto.getId()==null){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//检查状态
if(checkStatus(status)){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//2.修改状态
ApUserRealname apUserRealname = new ApUserRealname();
apUserRealname.setId(dto.getId());
apUserRealname.setStatus(status);
if(dto.getMsg() != null){
apUserRealname.setReason(dto.getMsg());
}
updateById(apUserRealname);
//3.如果审核状态是通过,创建自媒体账户,创建作者信息
if(status.equals(UserConstants.PASS_AUTH)){
//创建自媒体账户,创建作者信息
ResponseResult result = createWmUserAndAuthor(dto);
if(result != null){
return result;
}
}
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
@Autowired
private ApUserMapper apUserMapper;
@Autowired
private WemediaFeign wemediaFeign;
/**
* 创建自媒体账户,创建作者信息
* @param dto
*/
private ResponseResult createWmUserAndAuthor(AuthDto dto) {
//获取ap_user信息
Integer apUserRealnameId = dto.getId();
ApUserRealname apUserRealname = getById(apUserRealnameId);
ApUser apUser = apUserMapper.selectById(apUserRealname.getUserId());
if(apUser == null){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
WmUser wmUser = wemediaFeign.findByName(apUser.getName());
//创建自媒体账户
if(wmUser == null){
wmUser = new WmUser();
wmUser.setApUserId(apUser.getId());
wmUser.setCreatedTime(new Date());
wmUser.setName(apUser.getName());
wmUser.setPassword(apUser.getPassword());
wmUser.setSalt(apUser.getSalt());
wmUser.setPhone(apUser.getPhone());
wmUser.setStatus(9);
wemediaFeign.save(wmUser);
}
//创建作者
createAuthor(wmUser);
apUser.setFlag((short)1);
apUserMapper.updateById(apUser);
return null;
}
@Autowired
private ArticleFeign articleFeign;
/**
* 创建作者
* @param wmUser
*/
private void createAuthor(WmUser wmUser) {
Integer apUserId = wmUser.getApUserId();
ApAuthor apAuthor = articleFeign.findByUserId(apUserId);
if(apAuthor == null){
apAuthor = new ApAuthor();
apAuthor.setName(wmUser.getName());
apAuthor.setCreatedTime(new Date());
apAuthor.setUserId(apUserId);
apAuthor.setType(UserConstants.AUTH_TYPE);
articleFeign.save(apAuthor);
}
}
/**
* 检查状态
* @param status
* @return
*/
private boolean checkStatus(Short status) {
if(status == null || (!status.equals(UserConstants.FAIL_AUTH) && !status.equals(UserConstants.PASS_AUTH))){
return true;
}
return false;
}
在heima-leadnews-common中定义常量类
public class UserConstants {
public static final Short FAIL_AUTH = 2;
public static final Short PASS_AUTH = 9;
public static final Integer AUTH_TYPE = 2;
}
3.在heima-leadnews-user中的ApUserRealnameController中完善authPass和authFail方法
@RestController
@RequestMapping("/api/v1/auth")
public class ApUserRealnameController implements ApUserRealnameControllerApi {
@Autowired
private ApUserRealnameService apUserRealnameService;
.......
/**
* 审核通过
* @param dto
* @return
*/
@PostMapping("/authPass")
@Override
public ResponseResult authPass(@RequestBody AuthDto dto) {
return apUserRealnameService.updateStatusById(dto,UserConstants.PASS_AUTH);
}
/**
* 审核失败
* @param dto
* @return
*/
@PostMapping("/authFail")
@Override
public ResponseResult authFail(@RequestBody AuthDto dto) {
return apUserRealnameService.updateStatusById(dto,UserConstants.FAIL_AUTH);
}
}
4.在heima-leadnews-admin-gateway的application.yml文件中增加关于用户微服务的网关配置
routes:
# 平台管理
......
# user微服务
- id: user
uri: lb://leadnews-user
predicates:
- Path=/user/** #http://localhost:6001/admin/api/v1/channel/list -->http://localhost:9001/api/v1/channel/list
filters:
- StripPrefix= 1
5.测试
数据准备
在leadnews-user库中ap_user表中新增一条数据
ap_user_realname表中新增一条数据,注意user_id字段要与ap_user表中对应
启动工程清单
- nacos
- heima-leadnews-admin
- heima-leadnews-admin-gateway
- heima-leadnews-article
- heima-leadnews-user
- heima-leadnews-wemedia
测试
登录操作
用户审核通过操作
5.综合测试
导入全新的前端项目,启动前端项目,进行综合测试