第三十九节 业务拆解

亮子 2025-04-22 10:59:13 178 0 0 0

1、项目创建

image.png

2、管理员登录

(1)账号长度必须在3到6个字符
(2)密码长度必须在4到6个字符

image.png

3、商户列表+排序+分页+多字段模糊查询

image.png

4、用户不登录不能使用任何功能

(1)守卫路由

// 全局守卫路由
router.beforeEach((to, from, next) => {

    //--1 白名单
    if(to.name === 'login') {
      next();
      return;
    }
    if(to.name === 'reg') {
      next();
      return;
    }

    //--2 检查用户是否认证,例如检查token
    let token = window.sessionStorage.getItem('token');
    // to.name
    if(token == null) {
      next({ path: '/login', query: { redirect: to.fullPath } });
    }
    else {
      next();
    }
});

(2)请求携带token

// 3、请求拦截器
service.interceptors.request.use(
    async config => {
        console.log("request url=" + config.url);
        // 每次发送请求之前判断vuex中是否存在token        
        // 如果存在,则统一在http请求的header都加上token,这样后台根据token判断你的登录情况
        // 即使本地存在token,也有可能token是过期的,所以在响应拦截器中要对返回状态进行判断 
        config.headers.token = window.sessionStorage.getItem('token');
        return config;
    },
    error => {
        return Promise.reject(error);
    }
)

(3)401页面跳转

// 4、响应拦截器
service.interceptors.response.use(
    response => {
        if (response.status === 200) {
            return Promise.resolve(response); //进行中        
        } else {
            return Promise.reject(response); //失败       
        }
    },
    // 服务器状态码不是200的情况    
    error => {
        if (error.response.status) {
            switch (error.response.status) {
               
                case 401:
                    // 401: 未登录                
                    router.push('/login');
                    break          
                default:
            }
            return Promise.reject(error.response);
        }
    }
);

(4)网关全局过滤器

package com.bwie.filter;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.concurrent.TimeUnit;

/**
 * @author 军哥
 * @version 1.0
 * @description: TODO
 * @date 2025/4/22 13:20
 */

@Configuration
@Order(1)
public class MyGlobalFilter implements GlobalFilter {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //--1 获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String url = request.getURI().getPath();
        System.out.println("请求路径:"+url);

        //--2 白名单
        // 登录接口/注册接口/发送验证码
        if(url.contains("/adminLogin")) {
            System.out.println("登录接口白名单:" + url);
            return chain.filter(exchange);
        }
        if(url.contains("/userReg")) {
            System.out.println("注册接口白名单:" + url);
            return chain.filter(exchange);
        }

        //-- 检查并验证token

        // 获取请求头中的token
        String token = request.getHeaders().getFirst("token");
        if(token == null || token.isEmpty()) {
            // token为空,进行拦截,并返回401状态码
            System.out.println("token为空:" + url);
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        // 获取redis中的token
        Claims body = Jwts.parser().setSigningKey("123456").parseClaimsJws(token).getBody();
        Integer userId = body.get("userId", Integer.class);
        String redisKey = "token-" + userId;
        String redisToken = stringRedisTemplate.opsForValue().get(redisKey);
        if(redisToken == null || redisToken.isEmpty()) {
            System.out.println("token已过期:" + url);
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        // 比较两个token
        if(!token.equals(redisToken)) {
            System.out.println("token错误:" + url);
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        //-- token续期(续期60分钟)
        stringRedisTemplate.expire(redisKey, 60, TimeUnit.MINUTES);

        //-- 放行(转发)
        System.out.println("放行:" + url);

        return chain.filter(exchange);
    }
}

5、商户注册

(1)账号必须是5到16个字符
(2)密码必须包含字母和数字,并且最小长度6位
(3)真实姓名必须是汉字
(4)请输入正确的手机号
(5)请输入正确的邮箱

image.png

6、商户状态显示+审批按钮

image.png

7、商户审批功能

(1)商户信息只读回显
(2)审批使用单选框组件
(3)审批驳回,必须填写驳回理由
(4)审批完成后,刷新列表

image.png

8、商户信息修改

image.png

9、使用git管理代码以及代码上传

69500021ddc96e25e7605caf1fd96fe8.png
02a7000c3cee85ad83989833cece7ae1.png
84526021fe117d90d68a64a8127693e3.png
34e557866090f7f7dcf7647c2246261e.png

商户头像+单图图片上传+修改

(1)使用docker安装FastDFS服务
(2)SpringBoot集成FastDFS
(3)使用FastDFS实现文件上传接口
(4)实现个人信息修改
(5)个人信息修改可以修改自己的头像
(6)商户列表显示头像

image.png

image.png

11、商户批量删除