前言
最近一周我花了大量时间在源码的阅读上,这极大的消耗了我对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,后面学完结合整体逻辑来调整吧。接下来前端要学文章发布的业务,我后端这方面还没写,得一边结合前端逻辑一边写后端了,是个大工程,所以先在此做个总结。