java转go第五阶段(1) react学习与项目的前后端分离


前言

最近一周我花了大量时间在源码的阅读上,这极大的消耗了我对go的学习热情,另外我最初转go的目的是通过一个培训。而目前的学习计划与培训的内容有了一些出入,培训采取广度优先的策略,安排了对全栈的学习。可能学习内容并不是很深,但仍然有许多的内容是我没接触过的,比如react、docker等。所以我需要调整我的学习计划,暂时停止对源码的深入学习,采取用项目驱动的方式,快速掌握最核心的功能完成项目实践的需要。


一、学习经过

  • 看了很多GORM源码的博客,稍微明白点的这篇还有这篇,但都太过零碎,感觉没有一根线头能将整个串起来,看完了数据库连接的初始化决定放一放,以后功力深了再来学
  • 写项目的时候把文件分成控制层服务层这些,才发现项目没有依赖注入,spring用习惯了真的产生依赖了
  • 想起刚开始学的时候看的一个仿苍穹外卖的项目,现在回头去看,大佬封装写的太漂亮了
  • 项目进行前后端分离又干不下去了,家人们我又要开始学前端了,react开学
  • 主要是看黑马的react课,我个人的学习情况是在redux以前都还能听懂,到了redux开始弄不明白了,只知道这是个在内存存东西的组件,然后存取的一套流程根本不明白在干什么,但黑马又把它拆解的非常零件化,照猫画虎每个步骤来就行了,这点对我来说是一个模糊的点,以后考虑是否要弄明白,因为问了前端的同学说这个以后不是很常用。后面美团案例我跳过了,看完路由直接接上day6的东西,从这里开始跟着敲,改造我的前端项目才有了学起来的感觉。

二、学习总结

我的后端项目
我的前端项目

1 目录结构

来一个我认为好看的目录结构
在这里插入图片描述

2 关于依赖注入

网上看到谷歌有个工具wire可以帮忙进行依赖注入,但我了解之后觉得太麻烦了,还不如手动注入方便,看了大佬的项目,发现它是在路由控制的地方统一注入的,一句话就行也挺方便
在这里插入图片描述
每一层都有有个new方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3 后端跨域处理

这一段是通义灵码为我自动生成的,是我前后端分离以后出现了跨域问题,前端有时会发option请求给后端,最开始我没配的时候会导致请求失败,配了以后就通了,具体什么原理还没弄明白,标记一下以后了解。

	// 配置CORS中间件
	config := cors.DefaultConfig()
	config.AllowAllOrigins = true
	config.AllowMethods = []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}
	config.AllowHeaders = []string{"Origin", "Content-Length", "Content-Type", "Authorization"}
	r.Use(cors.New(config))

4 casbin权限认证

修改了一下matchers,因为想给某个角色添加权限以前需要一条条路由的敲,但加了keymatch以后可以用*代替字符进行匹配,这样我匹配/user/info这种路径的时候就不用再一个个添加了
在这里插入图片描述

以前的

m = (g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act) || g(r.sub,"admin")

修改后的

m = (g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && r.act == p.act) || g(r.sub,"admin")

5 前端学习梳理

1 钩子函数

说一下我个人的浅薄理解,react最大的特点就是钩子函数的存在,它使得组件化的思想得到进一步的实现。有了HOOK的存在一个函数便可以成为一个组件,可以自由设置和修改它的状态来渲染出不同的效果,极大的实现了代码的复用,使得逻辑更加清晰,一个文件里面能清除的通过hook区分都是在做什么,代码的可读性也增强了。
梳理一下我学到的很有用的hook:
1 useState
一个标准的useState长这样,分为状态名username(可更改),修改状态的函数setUsername(可根据状态名更改),初始化赋值函数useState.
这个hook的作用是修改状态值,并重新渲染,它可以保证对值的修改能实时进行渲染更新。

const [username, setUsername] = useState('');
onChange={(e) => setUsername(e.target.value)}

2 useRef
两个使用方法,一个是作为不会自动渲染的useState,用来保存一些不需要渲染的值比如计数器这种

 const countRef = useRef(0);
 countRef.current++;
 console.log('Count:', countRef.current);

另一个比较复杂我也不是很懂,姑且一说,作为一个“标签”去连接真实的DOM元素,方便对DOM元素进行定位,获取它的状态,这种用的比较多

const chartRef = useRef(null);
<div id="main" ref={chartRef} style={{width: 600, height: 400}}/>
const chartDom = chartRef.current; // 获取真实 DOM
const myChart = echarts.init(chartDom); // 在此 DOM 上初始化图表

3 useEffect
用于在函数组件中执行副作用操作,或者用我理解的话叫做附带操作。结构如下
当函数组件被加载的时候useEffect会自动执行一遍逻辑操作,当state变量更新时会再次执行逻辑操作,在函数组件卸载时会执行return里的逻辑。state可以没有,那样就不会在变量更新时执行操作。

useEffect(() => {
        console.log('这是一段逻辑操作');
                return () => {
            console.log('这是卸载组件时执行的操作');
        };
    }, [state]);

4 useNavigate
用于在函数组件中进行导航

navigate('/about'); //绝对路径导航
navigate(`./${userId}`); // 相对路径导航
navigate('/dashboard', { state: { user } }); //携带状态值
navigate(-1); // 回退到上一个页面

2前端项目目录结构

在这里插入图片描述

3 request.jsx

文件对axios进行了封装处理,会设置请求的基础路径,拦截请求和响应并进行处理,感觉很像java里的切片或者gin里面的中间件,还是很好理解的。

// axios的封装处理
import axios from "axios"
import {getToken, removeToken} from "./token.jsx";
// 1. 根域名配置
// 2. 超时时间
// 3. 请求拦截器 / 响应拦截器

const request = axios.create({
    baseURL: 'http://localhost:8080',
    timeout: 5000
})

// 添加请求拦截器
// 在请求发送之前 做拦截 插入一些自定义的配置 [参数的处理]
request.interceptors.request.use((config) => {
    // 操作这个config 注入token数据
    // 1. 获取到token
    // 2. 按照后端的格式要求做token拼接
    const token = getToken()
    if (token) {
        config.headers.Authorization= `Bearer ${token}`
    }
    config.headers["Content-Type"] = "application/json";
    return config
}, (error) => {
    return Promise.reject(error)
})

// 添加响应拦截器
// 在响应返回到客户端之前 做拦截 重点处理返回的数据
request.interceptors.response.use((response) => {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    // 设置token


    return response
}, (error) => {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    // 监控401 token失效
    console.dir(error)
    //TODO 错误拦截之后进行了一些处理,但登录失败仍然会进行自动刷新跳转到api.protab.cn
    if (error.response.status === 401 || error.response.status === 403) {
        // 清除token
        removeToken()
        if (error.response.status === 401) {
            // 检查错误信息是否包含“用户名或密码错误”
            if (error.response.data.message && error.response.data.message.includes("用户名或密码错误")) {
                // 提示错误信息
                alert('用户名或密码错误,请重试。');
            } else {
                // 跳转到登录页面
                window.location.href = '/login';
            }
        } else if (error.response.status === 403) {
            // 返回之前的页面
            window.history.back();
            // 提示错误信息
            alert('您没有权限访问该页面,请联系管理员。');
        }
    }
    // window.location.reload()
    return Promise.reject(error)
})

export { request }


总结

前端项目留了一些bug,但有些关于业务逻辑,比如好像因为严格模式的原因,会发送两次获取用户信息的请求,在我这会导致用户权限不通过会返回两次的bug,后面学完结合整体逻辑来调整吧。接下来前端要学文章发布的业务,我后端这方面还没写,得一边结合前端逻辑一边写后端了,是个大工程,所以先在此做个总结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值