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

黑马头条第八天实战(上)

D8

1)登录功能需求说明

  • 用户根据用户名和密码登录
  • 密码需要手动加盐验证
  • 需要返回用户的token和用户信息

2)模块搭建思路步骤

2.1)模块作用

先捋一下之前搭模块干了啥

image-20240911195444754

feign-api 远程调用

自媒体保存时调用远程客户端进行增加文章,说白了就是数据拷贝到另一个数据库展示

定时任务客户端,自媒体审核完发布后根据发布时间进行延迟任务

这一块用到了redis的zset和list队列 然后判断了时间,数据库同步问题

好像和登录没关系ok跳过

gateway 网关服务

好像是起到一个转发api的作用,我们先启动user/app网关服务看看请求路径找下规律

其实也可以不用,启动,直接启动前端nginx发请求就行

image-20240911200238344

前面带了一个app,估计和nginx代理那些差不多,识别/app/**,最后将/app去掉,定向到/** 路径下

okok一起来看下网关服务是怎么设置的

image-20240911200530214

过滤器,鉴别token的,这个应该都一样,我们直接拷贝就行。jWT工具和引导类上的注解

@SpringBootApplication
@EnableDiscoveryClient

大差不差,全拷贝,就改配置文件即可,然后配置nacos,这看起来好像也没那么难,对吧?

image-20240911201014375

2.2)模块配置文件

网关
server:port: 6001
spring:application:name: leadnews-admin-gatewaycloud:nacos:discovery:server-addr: 192.168.233.136:8848config:server-addr: 192.168.233.136:8848file-extension: yml

同样的模仿其他服务看看

image-20240911215924713

server:port: 51805
spring:application:name: leadnews-admincloud:nacos:discovery:server-addr: 192.168.233.136:8848config:server-addr: 192.168.233.136:8848file-extension: yml

2.3)引导类

网关
package com.heima.admin.gateway;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
@EnableDiscoveryClient
public class AdminGatewayApplication {public static void main(String[] args) {SpringApplication.run(AdminGatewayApplication.class,args);}
}
admin服务
package com.heima.admin;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.admin.mapper")
public class AdminApplication {public static void main(String[] args) {SpringApplication.run(AdminApplication.class,args);}
}

那nacos是怎么配置的?同样模仿别的服务看看

image-20240911202200065

结构和application差不多但是为什么要写到这里面?

application.yml 由springboot内部管理在启动应用时加载,也就是说,当你修改了application.yml后,需要重新启动springboot

相当于是一个项目已经编码好了,打好了jar包,当你部署到服务器上时,发现配置文件不满意,因此你还得重新修改,打包,部署, 不过有另一种方法,在jar包的同级目录下创建配置文件yml,指定即可,但是,也挺麻烦的,也不好统一管理,还有一种就是以命令行的参数指定配置文件,不过这样一来,又涉及到重新部署jar包,在生产环境下,当你服务停止了1分钟,你的客户们就会比比赖赖,这什么破网站,天天崩溃,我还是找找有没有更好一点的替代品吧

好的因此我们总结出一个好处 (面试的时候可以吹牛逼了)

配置文件动态更新

并且,单体项目还好,如果是多个微服务呢?岂不是一堆的application.yml,也不好管理是吧,在nacos,你可以统一的在一个页面上进行修改,嘎嘎方便,第二个好处是

方便统一管理

2.4)配置详解

这个id就是springboot项目指定ip和服务名所找到的配置,然后合并springboot内部和nacos上的

image-20240911203154850
2.4.1)CORS配置
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# 文章微服务- id: articleuri: lb://leadnews-articlepredicates:- Path=/article/**filters:- StripPrefix= 1# 搜索微服务- id: leadnews-searchuri: lb://leadnews-searchpredicates:- Path=/search/**filters:- StripPrefix= 1
  • globalcors:全局跨域资源共享 cross origin resource share

  • add-to-simple-url-handler-mapping: true: 表示将cors配置添加到url映射,以便处理跨域请求 (后端跨域问题解决)

  • corsConfigurations:跨域配置

  • ‘[/**]’: 针对所有的请求

  • allowedHeaders: "\*": 允许所有请求头。

    允许所有请求头的键key对应的值value

    常见请求头包括

    • Content-Type: 指定请求体的内容类型。
    • Authorization: 用于携带认证信息。(token)
    • 自定义请求头: 例如 X-Custom-Header

    例子

    GET /api/resource HTTP/1.1
    Host: example.com
    Content-Type: application/json
    Authorization: Bearer token
    X-Custom-Header: customValue
    
  • allowedOrigins: "\*": 指定了所有源也就是80/443 或是https/http 或者不同的域名ww.cn xx.cn 请求该服务器资源

  • allowedMethods:

    • 允许的 HTTP 方法,包括 GET、POST、DELETE、PUT 和 OPTIONS。

wc OPTIONS这是啥请求第一次见,查询得知是在跨域请求的情况下,浏览器发起的预检请求

当你从一个域名发post到另一个域名时,浏览器会发送OPTIONS请求(内容携带了实际请求)

OPTIONS /api/resource HTTP/1.1
Origin: http://frontend.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type

服务器根据cors策略返回允许的跨域方法和头部消息

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://frontend.example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type

允许了get post 和options预检,和允许的头键名Content-Type

2.4.2)路由配置
  • routes: 定义所有路由
  • - id: user: 路由标识符,给开发人员区分用的
  • uri: lb://leadnews-user: 表示负载均衡的服务名,(如果该服务下有多台主机,采用不同机制进行负载均衡可能,轮询?随机?加权?就记得这三种)
    类似与代理,最终代理对象是leadnews-user服务
  • predicates: 翻译了一下,叫断言?肯定?声明? 我觉得应该叫regular好一点,因为该数组内容就是 什么特征规则的请求会被转发
  • - Path=/user/**: 所有/user打头的符合规则,开始转发到user服务
  • filters: 路由过滤器
  • - StripPrefix= 1: strip翻译为带,剥离,脱衣,prefix表示前缀, 整体意思为剥离由/分隔的前缀路径第一个 /user(第一个)/app(第二个)
    然后剩下的路径转发到 user服务的/user/app接口

突然想起来了,nginx里有个代理app前缀好像,在nginx里也做了负载均衡,666双重负载均衡,

image-20240911210100618

然后代理到51601,然后由nacos网关路由再代理到 user服务,层层脱衣了属于是

接下来我们再看一下具体的微服务怎么配的

image-20240911215509948

user和wemedia的服务配置了数据库,mybatis-plus

那我们就在admin服务下拷贝过去这些共同配置

Tip这里nginx给的conf配置文件代理到后端网关端口是6001,因此我们admin网关配置文件也得是6001,而不是在最后一个网关服务的端口+1

2.5)nacos服务配置

admin服务
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://192.168.233.136:3306/leadnews_admin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTCusername: rootpassword: 123456
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:mapper-locations: classpath*:mapper/*.xml# 设置别名包扫描路径,通过该属性可以给包中的类注册别名type-aliases-package: com.heima.model.admin.pojos
网关服务
spring:cloud:gateway:globalcors:add-to-simple-url-handler-mapping: truecorsConfigurations:'[/**]':allowedHeaders: "*"allowedOrigins: "*"allowedMethods:- GET- POST- DELETE- PUT- OPTIONroutes:# 平台管理- id: adminuri: lb://leadnews-adminpredicates:- Path=/admin/**filters:- StripPrefix= 1

2.6启动服务测试

image-20240911222205802

3)登录功能实现

盖好了地基了 现在就简单多了,嘎嘎堆shi就行

  • 用户根据用户名和密码登录
  • 密码需要手动加盐验证
  • 需要返回用户的token和用户信息

实体类

接口接收数据要封装到这里面的玩意,在资料里有提供,这里我直接放这里让你复制不用下载

AdUser
package com.heima.common.admin.pojos;import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;import java.io.Serializable;
import java.util.Date;/*** <p>* 管理员用户信息表* </p>** @author itheima*/
@Data
@TableName("ad_user")
public class AdUser implements Serializable {private static final long serialVersionUID = 1L;/*** 主键*/private Integer id;/*** 登录用户名*/@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("phone")private String phone;/*** 状态0 暂时不可用1 永久不可用9 正常可用*/@TableField("status")private Integer status;/*** 邮箱*/@TableField("email")private String email;/*** 最后一次登录时间*/@TableField("login_time")private Date loginTime;/*** 创建时间*/@TableField("created_time")private Date createdTime;}
ApUserRealname
package com.heima.common.admin.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_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;}

接口定义

wc需求说明里毛都没,自己看前端请求吧谢

image-20240911223659690

封装一个只有这俩字段的dto

AdUserDto

package com.heima.model.admin.dtos;import lombok.Data;@Data
public class AdUserDto {private String name;private String password;
}

由于该请求负载 为请求体,接收加RequestBody注解 如果不加注解,无法解析为Dto,其格式为Content-Type对应的值

controller后面再贴上来,因为还没写service(我觉得先service再controller的顺序好一点,不然你一开始给个破接口return null后面还要改,重复操作)

Service

public interface AdminLoginService {/*** 管理员登录* @param adUserDto 密码和用户名dto* @return*/ResponseResult login (AdUserDto adUserDto);
}

Impl思路

密码加盐对比?我回想一下,好像是根据前端传来的用户名,查出密码和盐,盐+前端初始密码生成加密后的 密文与数据库加密后的密文比对,如果一致则通过

okok,那我们就把用户查出来先

1.查询用户,不为空则查盐+原始密码进行加密处理,比对数据库 (mapper还没加呢大哥)

mapper

@Mapper
public interface AdLoginMapper extends BaseMapper<AdUser> {
}

回归正题

Impl代码

package com.heima.admin.service.impl;import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.admin.mapper.AdminLoginMapper;
import com.heima.admin.service.AdminLoginService;
import com.heima.model.admin.dtos.AdUserDto;
import com.heima.model.admin.pojos.AdUser;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;@Service
@Slf4j
public class AdminLoginServiceImpl implements AdminLoginService {@Autowiredprivate AdminLoginMapper adminLoginMapper;/*** 管理员登录** @param adUserDto 密码和用户名dto* @return*/@Overridepublic ResponseResult login(AdUserDto adUserDto) {// 1.参数校验if (adUserDto != null) {// 1.查询用户,不为空则查盐+原始密码进行加密处理,比对数据库// 我的盐我决定,先放盐!!在放密码 md5加密需要获取字节码进行加密AdUser dbAdUser = adminLoginMapper.selectOne(Wrappers.<AdUser>lambdaQuery().eq(AdUser::getName, adUserDto.getName()));if (dbAdUser == null) {return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);}String md5DigestAsHex = DigestUtils.md5DigestAsHex((dbAdUser.getSalt() + adUserDto.getPassword()).getBytes());if (md5DigestAsHex.equals(dbAdUser.getPassword())) {log.info("登录成功!");return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);}}return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}
}

测试

让给我们来debug启动测试一下吧!,谢特,忘记补controller了

controller

@RestController
@RequestMapping("/login")
public class AdminLoginController {@Autowiredprivate AdminLoginService adminLoginService;@PostMapping("/in")public ResponseResult login(@RequestBody AdUserDto dto){return  adminLoginService.login(dto);}
}

image-20240911230636377

gogogo

image-20240911230753570

很顺利的进入了噢老铁

image-20240911231059248

mmp 数据库错了?

image-20240911231126330

说我user库里的ad_user表不存在? 等等,user库?

image-20240911231232213

oh谢,忘记改了,问题不大,md这网关一次性用品啊,每次都要重启服了

image-20240911231443650

查询成功

image-20240911231506509

比对成功,最后返回SUCCESS

image-20240911231621501

这前端干啥吃的,怎么成功不给我跳转呢

image-20240911231700783

还要返回name?

image-20240912094749022

结构发现data里需要包含user对象还有 token值,那我们就给他返回一个map

登录成功后添加

  Map<String, Object> map = new HashMap<>();String token = AppJwtUtil.getToken(Long.valueOf(dbAdUser.getId()));map.put("user",dbAdUser);map.put("token",token);return ResponseResult.okResult(map);
image-20240912095639931

4)频道管理

4.1)新增需求说明

image-20210725225940936

  • 前台输入内容进行频道的保存
  • 频道名词不能重复

image-20240912100135301

image-20240912100340937

接口url, 网关6001,转发到服务wemedia,

负载内容字段

  • description
  • name
  • ord
  • status

首先来给网关增加个服务先

 # 自媒体管理- id: wemediauri: lb://leadnews-wemediapredicates:- Path=/wemedia/**filters:- StripPrefix= 1

image-20240912100309890

在原来的服务上加save接口即可

4.1.1)实现步骤
dto
package com.heima.model.wemedia.dtos;import lombok.Data;@Data
public class WmChannelDto {private String description;private String name;private Short ord;private Integer status;
}
service
 ResponseResult saveChannel(WmChannelDto wmChannelDto);
impl
 @Overridepublic ResponseResult saveChannel( WmChannelDto wmChannelDto) {WmChannel wmChannel = new WmChannel();BeanUtils.copyProperties(wmChannelDto,wmChannel);return ResponseResult.okResult(save(wmChannel));}
controller
@PostMapping("/save")public  ResponseResult saveChannel(@RequestBody WmChannelDto dto){return wmchannelService.saveChannel(dto);}

image-20240912102510055

新增成功

4.2)查询

  • 查询需要按照创建时间倒序查询
  • 按照频道名称模糊查询
  • 可以按照状态进行精确查找(1:启用 true 0:禁用 false)
    这一块前端没传数据过来,不做了
  • 分页查询

。。。。熟悉的crud既视感

image-20240912103625751

  • name
  • page
  • size
dto
@Data
public class WmChannelSeachDto {String name;int page;int size;
}
service

wm服务下

  /*** 管理员频道列表* @param wmChannelSeachDto* @return*/ResponseResult listForAdmin(WmChannelSeachDto wmChannelSeachDto);
impl
  /*** 管理员频道列表** @param wmChannelSeachDto* @return*/@Overridepublic ResponseResult listForAdmin(WmChannelSeachDto wmChannelSeachDto) {// - 查询需要按照创建时间倒序查询LambdaQueryWrapper<WmChannel> wrapper = new LambdaQueryWrapper<>();// WmChannel::getCreatedTime是一种方法引用(引用字段),// 你也可以使用Lambda 表达式item->item.getCreatedTiemwrapper.orderByDesc(WmChannel::getCreatedTime);// - 按照频道名称模糊查询wrapper.like(StringUtils.isNotBlank(wmChannelSeachDto.getName()),WmChannel::getName, wmChannelSeachDto.getName());// - 可以按照状态进行精确查找(1:启用   true    0:禁用   false)// wrapper.eq(Integer.valueOf(wmChannelSeachDto.getStatus())!=null,WmChannel::getStatus,wmChannelSeachDto.getStatus());// - 分页查询IPage page = new Page(wmChannelSeachDto.getPage(), wmChannelSeachDto.getSize());page(page, wrapper);ResponseResult responseResult = new PageResponseResult(wmChannelSeachDto.getPage(), wmChannelSeachDto.getSize(), (int) page.getTotal());responseResult.setData(page.getRecords());return responseResult;}
controller
    /*** 管理员的频道列表*/@PostMapping("/list")public ResponseResult listForAdmin(@RequestBody WmChannelSeachDto dto) {return wmchannelService.listForAdmin(dto);}

image-20240912112624537

4.3)修改

4.3.1)需求说明

image-20240912114609586

  • 点击编辑后可以修改频道
  • 如果频道被引用则不能禁用(根据当前频道id查询wmNews下有没有人引用)

image-20240912114100186

description

id

name

ord

status

实体

和channel实体大致差不多,就用这个了

service
 /**管理员修改操作** @param wmChannel* @return*/ResponseResult updateForAdmin(WmChannel wmChannel);
impl
/*** 管理员修改操作** @param wmChannel* @return*/@Overridepublic ResponseResult updateForAdmin(WmChannel wmChannel) {if (wmChannel != null) {// 如果用户禁用,查询wmNews表有无该频道,没有则可以禁用,有则返回错误if (!wmChannel.getStatus()) {// 找有和当前要禁用频道有一腿的news,有的话就报错给前面List<WmNews> wmNews = wmNewsMapper.selectList(Wrappers.<WmNews>lambdaQuery().eq(WmNews::getChannelId, wmChannel.getId()));if (wmNews!=null&&wmNews.size()>0) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "该频道下有文章,禁用失败");}}return ResponseResult.okResult(updateById(wmChannel));}// 编辑的参数校验return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}
controller
 /*** 管理员修改操作*/@PostMapping("/update")public ResponseResult updateForAdmin(@RequestBody WmChannel wmChannel) {return wmchannelService.updateForAdmin(wmChannel);}

测试

image-20240912120630282

image-20240912120646659

4.4)删除

只有禁用的频道才能删除

service
    /**管理员删除操作*** @return*/ResponseResult removeForAdmin(Integer id);
impl
  /*** 管理员删除操作** @return*/@Overridepublic ResponseResult removeForAdmin(Integer id) {WmChannel byId = getById(id);if (byId.getStatus()){return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"必须是禁用频道才能删除~");}return ResponseResult.okResult(removeById(id));}
controller
 /*** 管理员删除操作*/@GetMapping("/del/{id}")public ResponseResult removeForAdmin(@PathVariable("id") Integer id) {return wmchannelService.removeForAdmin(id);}
测试

image-20240912122702858

image-20240912122744132

5)敏感词管理

image-20240912122830900

  • 查询需要按照创建时间倒序查询
  • 按照敏感词名称模糊查询
  • 分页查询
dto
@Data
public class WmSensitiveDto {String name;int page;int size;
}
service
   /*** 敏感词分页查询*/ResponseResult selectList(WmSensitiveDto wmSensitiveDto);
impl
 /*** 敏感词分页查询** @param wmSensitiveDto*/@Overridepublic ResponseResult selectList(WmSensitiveDto wmSensitiveDto) {IPage<WmSensitive> page = new Page(wmSensitiveDto.getPage(), wmSensitiveDto.getSize());LambdaQueryWrapper<WmSensitive> wrapper = Wrappers.<WmSensitive>lambdaQuery().eq(StringUtils.isNotBlank(wmSensitiveDto.getName()), WmSensitive::getSensitives, wmSensitiveDto.getName());page(page,wrapper);ResponseResult pageResponseResult =new PageResponseResult(wmSensitiveDto.getPage(), wmSensitiveDto.getSize(), (int)page.getTotal());pageResponseResult.setData(page.getRecords());return pageResponseResult;}
controller
@RestController
@RequestMapping("/api/v1/sensitive")
public class WmSensitiveController {@Autowiredprivate WmSensitiveService wmSensitiveService;@PostMapping("/list")public ResponseResult selectList(@RequestBody WmSensitiveDto wmSensitiveDto){return wmSensitiveService.selectList(wmSensitiveDto);}
}

image-20240912135010559

service
 /*** 敏感词增加*/ResponseResult add(WmSensitive wmSensitive);
impl
 /*** 敏感词增加** @param wmSensitive*/@Overridepublic ResponseResult add(WmSensitive wmSensitive) {if (wmSensitive==null){return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}wmSensitive.setCreatedTime(new Date());return ResponseResult.okResult(wmSensitiveMapper.insert(wmSensitive));}
controller
@PostMappingpublic ResponseResult add(@RequestBody WmSensitive wmSensitive){return ResponseResult.okResult(wmSensitiveService.add(wmSensitive));}

service
/*** 敏感词修改*/ResponseResult update(WmSensitive wmSensitive);
impl
/*** 敏感词修改** @param wmSensitive*/@Overridepublic ResponseResult update(WmSensitive wmSensitive) {return ResponseResult.okResult(wmSensitiveMapper.updateById(wmSensitive));}
controller
@PostMapping("/update")public ResponseResult update(@RequestBody WmSensitive wmSensitive){return ResponseResult.okResult(wmSensitiveService.update(wmSensitive));}

controller 麻了,直接调mapper吧
 @Autowiredprivate WmSensitiveMapper wmSensitiveMapper; 
@PostMapping("/del/{id}")public ResponseResult delete(@PathVariable("id") Integer id){return ResponseResult.okResult(wmSensitiveMapper.deleteById(id));}

6)用户认证

  • 在app端的个人中心用户可以实名认证,需要材料为:姓名、身份证号、身份证正面照、身份证反面照、手持照片、活体照片(通过微笑、眨眼、张嘴、摇头、点头等组合动作,确保操作的为真实活体人脸。),当用户提交审核后就到了后端让运营管理人员进行审核

这里不涉及到任何的延迟队列以及消息发送,我们使用feign远程调用即可,具体操作参考添加文章后进入自动审核成功后添加到app端进行展示

  • 平台运营端查看用户认证信息,进行审核,其中审核包括了用户身份审核,需要对接公安系统校验身份证信息
  • 用户通过审核后需要开通自媒体账号(该账号的用户名和密码与app一致)

oh谢,看到现在才发现其实是有接口文档的

image-20240912204431707

OMG,付费内容了,只能下一个需求了

…jiodo玛德,在app端的个人中心用户可以实名认证 这一块是不能认证的,已经写死在了数据库,(可能一开始是有的,为了收米阉割了)

image-20240912210432420

我们直接遍历即可,由于数据库在user库,我们在user服务做文章即可…那用户认证推送功能阉割了只剩查询和通过审核和驳回了

dto (前面忘记继承请求dto然后校验page参数了,现在补救一下)
@Data
public class AuthDto extends PageRequestDto {/***              状态*             0 创建中*             1 待审核*             2 审核失败*             9 审核通过*/private Short status;// 申请人idprivate Integer id;// 驳回的信息private String msg;}
pojo
/*** <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;}
service
public interface ApUserAuthService {/*** 分页查询* @param authDto* @return*/ResponseResult selectList(AuthDto authDto);
}
impl
@Service
public class ApUserAuthServiceImplextends ServiceImpl<ApUserRealnameMapper,ApUserRealname>implements ApUserAuthService {/*** 分页查询** @param authDto* @return*/@Overridepublic ResponseResult selectList(AuthDto authDto) {// 分页数据校验authDto.checkParam();//设置分页信息Page<ApUserRealname> page = new Page<>(authDto.getPage(), authDto.getSize());LambdaQueryWrapper<ApUserRealname> wrapper = Wrappers.<ApUserRealname>lambdaQuery().eq(Integer.valueOf(authDto.getStatus()) != null, ApUserRealname::getStatus, authDto.getStatus());page(page,wrapper);ResponseResult result = new PageResponseResult(authDto.getPage(), authDto.getSize(), (int) page.getTotal());result.setData(page.getRecords());return result;}
}
controller
@RestController
@RequestMapping("/api/vi/auth")
public class ApUserAuthController {@Autowiredprivate ApUserAuthService apUserAuthService;@PostMapping("/list")public ResponseResult selectList(@RequestBody AuthDto authDto){return  ResponseResult.okResult(apUserAuthService.selectList(authDto));}
}
nacos
# 平台管理- id: useruri: lb://leadnews-userpredicates:- Path=/user/**filters:- StripPrefix= 1

驳回/同意(改)

service
    /*** 驳回/同意申请* @param authDto* @return*/ResponseResult updateStatus(AuthDto authDto);
常量
package com.heima.common.constants;public class UserConstants {public static final Short PASS_AUTH = 9;public static final Short FAIL_AUTH = 2;public static final Integer AUTH_TYPE = 2;
}
impl

思路,更改状态,搞在一个方法里即可

接口不同,调用方法一样 (接口里修改short)

如果是驳回,不传status,直接设置为2,如果是同意,把ap端的user查出来,然后拷贝相关信息

远程客户端可能注入会爆红,在引导类上加@EnableFeignClients(basePackages = “com.heima.apis”)

此处想着学一下 示例代码的,不小心看了点答案,罪过QAQ

 /*** 驳回/同意申请,修改状态为2** @param authDto* @return*/@Overridepublic ResponseResult updateStatus(AuthDto authDto,Short status) {// 默认不给status就是拒绝ApUserRealname apUserRealname = new ApUserRealname();apUserRealname.setStatus(status);apUserRealname.setId(authDto.getId());if (StringUtils.isNotBlank(authDto.getMsg())) {apUserRealname.setReason(authDto.getMsg());}updateById(apUserRealname);// 如果是同意申请那就创建自媒体账号if (status == UserConstants.PASS_AUTH) {return createWmAccount(authDto);}return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);}@Autowiredprivate ApUserMapper apUserMapper;@Autowiredprivate IWemediaClient wemediaClient;private ResponseResult createWmAccount(AuthDto authDto) {// 判断在app端有无该用户ApUser apUser = apUserMapper.selectById(authDto.getId());if (apUser == null) {return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);}// 如果有该用户,拷贝ap端表的数据到WmUser,后续创建insert即可WmUser wmUser = new WmUser();wmUser.setApUserId(apUser.getId());wmUser.setSalt(apUser.getSalt());wmUser.setPassword(apUser.getPassword());wmUser.setStatus(Integer.valueOf(UserConstants.PASS_AUTH));wmUser.setPhone(apUser.getPhone());wmUser.setName(apUser.getName());// okok.开始插入,等等,这里好像没wmUser的mapper啊// 使用远程客户端,feign先写接口,然后要到达的服务层实现,要远程到哪就将客户端设置到哪的意思,// 注入客户端调方法wemediaClient.saveWmAccount(wmUser);apUser.setFlag((short)1);apUserMapper.updateById(apUser);return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);}
controller
/***  驳回/同意申请*/@PostMappingpublic ResponseResult updateStatus(@RequestBody AuthDto authDto){return apUserAuthService.updateStatus(authDto);}

相关文章:

黑马头条第八天实战(上)

D8 1&#xff09;登录功能需求说明 用户根据用户名和密码登录密码需要手动加盐验证需要返回用户的token和用户信息 2&#xff09;模块搭建思路步骤 2.1&#xff09;模块作用 先捋一下之前搭模块干了啥 feign-api 远程调用 自媒体保存时调用远程客户端进行增加文章&#x…...

swift qwen2-vl推理及加载lora使用案例

参考: https://swift.readthedocs.io/zh-cn/latest/Instruction/LLM%E5%BE%AE%E8%B0%83%E6%96%87%E6%A1%A3.html#%E5%BE%AE%E8%B0%83%E5%90%8E%E6%A8%A1%E5%9E%8B https://blog.csdn.net/weixin_42357472/article/details/142150209 SWIFT支持300+ LLM和50+ MLLM(多模态大模型…...

如何使用 Choreographer 进行帧率优化

Choreographer 是 Android 提供的一个工具类&#xff0c;专门用来协调 UI 帧的渲染。你可以通过 Choreographer 来精确控制帧的绘制时机&#xff0c;以优化帧率&#xff0c;确保应用的流畅度。以下是如何使用 Choreographer 进行帧率优化的详细步骤&#xff1a; 1. 理解 Chore…...

稳定驱动之选SiLM5350系列SiLM5350MDBCA-DG单通道隔离栅极驱动器(带内部钳位):工业自动化的可靠伙伴

SiLM5350系列SiLM5350MDBCA-DG是具体有10A峰值输出电流能力&#xff0c;单通道隔离式栅极驱动器。SiLM5350MDBCA-DG可提供内部钳位功能。驱动电源电压为4V至30V。3V至18V的宽输入VDDI范围使驱动器适合与模拟和数字控制器接口。所有电源电压引脚都有欠压锁定 (UVLO) 保护。 SiLM…...

鸿蒙OpenHarmony【轻量系统芯片移植】内核移植

移植芯片架构 芯片架构的移植是内核移植的基础&#xff0c;在OpenHarmony中芯片架构移植是可选过程&#xff0c;如果当前OpenHarmony已经支持对应芯片架构则不需要移植操作&#xff0c;在“liteos_m/arch”目录下可看到当前已经支持的架构&#xff0c;如表1&#xff1a; 表1 …...

多字节字符和宽字符

小时候&#xff0c;买东西的单位是一角、二角和五角&#xff0c;现在的单位是一元、五元和十元。人类社会的发展和计算机发展本质没啥两样&#xff0c;形态不同而已。 编码格式的历史 尽管早期只用ASCII码就可以表达所有字符&#xff0c;但计算机日益推广让其他国家不同语言的…...

C++缺省参数

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 缺省参数的概念 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时&#xff0c;如果没有指定实参则采用该形参的缺省值&#xff0c;否则…...

深度学习中的常用线性代数知识汇总——第一篇:基础概念、秩、奇异值

文章目录 0. 前言1. 基础概念2. 矩阵的秩2.1 秩的定义2.2 秩的计算方法2.3 秩在深度学习中的应用 3. 矩阵的奇异值3.1 奇异值分解&#xff08;SVD&#xff09;3.2 奇异值的定义3.3 奇异值的性质3.4 奇异值的意义3.5 实例说明3.6 奇异值在深度学习中的应用 0. 前言 按照国际惯例…...

MATLAB | R2024b更新了哪些好玩的东西?

Hey, 又到了一年两度的MATLAB更新时刻&#xff0c;MATLAB R2024b正式版发布啦&#xff01;&#xff0c;直接来看看有哪些我认为比较有意思的更新吧! 1 小提琴图 天塌了&#xff0c;我这两天才写了个半小提琴图咋画&#xff0c;MATLAB 官方就出了小提琴图绘制方法。 小提琴图…...

嵌入式硬件基础知识

嵌入式硬件基础知识涵盖了嵌入式系统中的硬件组成及其工作原理&#xff0c;涉及处理器、存储器、外设接口、电源管理等多个方面。这些硬件共同构成了一个完整的嵌入式系统&#xff0c;用于执行特定任务。下面我们来详细介绍嵌入式硬件的基础知识。 1. 嵌入式系统的组成 嵌入式…...

keepalived和lvs高可用集群

keepavlied和lvs高可用集群搭建 主备模式&#xff1a; 关闭防火墙和selinux systemctl stop firewalld setenforce 0部署master负载调度服务器 zyj86 安装ipvsadm keepalived yum install -y keepalived ipvsadm修改主节点配置 vim /etc/keepalived/keepalived.conf! Conf…...

在VMware部署银河麒麟系统

虚拟机镜像安装文件从下面下载: 银河麒麟桌面操作系统V10SP1 2403 下载地址_银河麒麟v10镜像iso下载-CSDN博客 虚拟机安装要求硬盘大小至少40G,我悬着60G 选择桥接网络安装后上不了网并且和本机也互相ping不通,因此选择Nat方式,然后重启,就可以上网 下面开始安装,第一个…...

git删除本地分支报错:error: the branch ‘xxx‘ is not fully merged

git删除本地分支报错&#xff1a;error: the branch xxx is not fully merged error: the branch xxx is not fully merged 直接&#xff1a; git branch -D xxx 就可以。 如果删除远程分支&#xff1a; git push origin --delete origin/xxx git强制删除本地分支 git branc…...

Tensorflow 兼容性测试-opencloudos

介绍 Tensorflow 兼容性测试: 测试 Tensorflow 各个版本在 OpenCloudOS Stream 的安装支持 操作系统 [rootlab101 ~]# cat /etc/os-release NAME"OpenCloudOS Stream" VERSION"23" ID"opencloudos" ID_LIKE"opencloudos" VERSION_I…...

Windows主机上安装CUPS服务端共享USB打印机实践心得

背景 平时主力机器是Windows&#xff0c;不想额外开一个Linux服务器来共享打印机。由于主力机平时也不关机&#xff0c;尝试在Windows上安装CUPS服务。 结论 先说结论&#xff0c;结论是可行&#xff0c;但是麻烦且不稳定&#xff0c;虚拟机方案少折腾&#xff0c;但是资源消耗…...

socket通讯原理及例程(详解)

里面有疑问或者不正确的地方可以给我留言。 对TCP/IP、UDP、Socket编程这些词你不会很陌生吧&#xff1f;随着网络技术的发展&#xff0c;这些词充斥着我们的耳朵。那么我想问&#xff1a; 什么是TCP/IP、UDP&#xff1f;Socket在哪里呢&#xff1f;Socket是什么呢&#xff1…...

vue3使用provide和inject传递异步请求数据子组件接收不到

前言 一般接口返回的格式是数组或对象&#xff0c;使用reactive定义共享变量 父组件传递 const data reactive([])// 使用settimout模拟接口返回 setTimeout(() > {// 将接口返回的数据赋值给变量Object.assign(data, [{ id: 10000 }]) }, 3000);provide(shareData, dat…...

对称矩阵的压缩存储

1.给自己出题&#xff1a;自己动手创造&#xff0c;画一个5行5列的对称矩阵 2.画图&#xff1a;按“行优先”压缩存储上述矩阵&#xff0c;画出一维数组的样子 3.简答&#xff1a;写出元素 i,j 与 数组下标之间的对应关系 4.画图&#xff1a;按“列优先”压缩存储上述矩阵&a…...

高阶数据结构之哈希表基础讲解与模拟实现

程序猿的读书历程&#xff1a;x语言入门—>x语言应用实践—>x语言高阶编程—>x语言的科学与艺术—>编程之美—>编程之道—>编程之禅—>颈椎病康复指南。 前言&#xff1a; 哈希表&#xff08;Hash Table&#xff09;是一种高效的键值对存储数据结构&…...

基于STM32设计的智能货架(华为云IOT)(225)

文章目录 一、前言1.1 项目介绍【1】项目背景【2】项目支持的功能【3】项目硬件模块组成【4】ESP8266工作模式配置【5】Android手机APP开发思路【6】项目模块划分1.2 项目开发背景【1】选题来源与背景【2】国内外研究现状【3】课题研究的目的和内容【4】参考文献【5】研究内容【…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

验证redis数据结构

一、功能验证 1.验证redis的数据结构&#xff08;如字符串、列表、哈希、集合、有序集合等&#xff09;是否按照预期工作。 2、常见的数据结构验证方法&#xff1a; ①字符串&#xff08;string&#xff09; 测试基本操作 set、get、incr、decr 验证字符串的长度和内容是否正…...

【2D与3D SLAM中的扫描匹配算法全面解析】

引言 扫描匹配(Scan Matching)是同步定位与地图构建(SLAM)系统中的核心组件&#xff0c;它通过对齐连续的传感器观测数据来估计机器人的运动。本文将深入探讨2D和3D SLAM中的各种扫描匹配算法&#xff0c;包括数学原理、实现细节以及实际应用中的性能对比&#xff0c;特别关注…...