Merge branch 'master' of github.com:FleyX/technology-note
This commit is contained in:
commit
5e889a6f89
@ -25,6 +25,8 @@ categories:
|
||||
|
||||
通过`@Transactional`开启事务。在`UserService`中定义一个事务方法`save`.然后在`UserController`中注入`UserDao`,并调用`save`方法。
|
||||
|
||||
<!-- more -->
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class UserService{
|
||||
|
@ -1,14 +1,12 @@
|
||||
---
|
||||
id: '2019-03-05-13-41'
|
||||
date: '2019/03/05 13:41'
|
||||
title: 'web跨域及cookie学习'
|
||||
tags: ['web', 'http请求跨域', 'cookie共享', 'get', 'post']
|
||||
id: "2019-03-05-13-41"
|
||||
date: "2019/03/05 13:41"
|
||||
title: "web跨域及cookie学习"
|
||||
tags: ["web", "http请求跨域", "cookie共享", "get", "post"]
|
||||
categories:
|
||||
- 'web'
|
||||
- "web"
|
||||
---
|
||||
|
||||
**本篇原创发布于:**[FleyX 的个人博客](http://tapme.top/blog/detail/2019-03-05-13-41)
|
||||
|
||||
  之前对于跨域相关的知识一致都很零碎,正好现在的代码中用到了跨域相关的,现在来对这些知识做一个汇总整理,方便自己查看,说不定也可能对你有所帮助。
|
||||
|
||||
**本篇主要内容如下:**
|
||||
@ -110,3 +108,5 @@ server {
|
||||
- Domain : `.example`,path : `/a`可获取 cookie:http://example:8081/a , https://localhost:8081/a , http://test.example:889/a
|
||||
|
||||
**注意**:在跨域请求中,即时目标地址有 cookie 且发起请求的页面也能读取到该 cookie,浏览器也不会将 cookie 自动设置到该跨域请求中。比如在http://localhost:8082/a页面中请求http://localhost:8081/abc,这两个地址下拥有共享cookie,http请求也不会携带cookie。
|
||||
|
||||
**本篇原创发布于:**[FleyX 的个人博客](http://tapme.top/blog/detail/2019-03-05-13-41)
|
||||
|
@ -1,22 +1,15 @@
|
||||
---
|
||||
id: '2019-03-01-18-52'
|
||||
date: '2019/03/01 18:52'
|
||||
title: 'spring boot 基于JWT实现单点登录'
|
||||
tags: ['spring-boot', 'SSO', '单点登录', 'jwt']
|
||||
id: "2019-03-01-18-52"
|
||||
date: "2019/03/01 18:52"
|
||||
title: "spring boot 基于JWT实现单点登录"
|
||||
tags: ["spring-boot", "SSO", "单点登录", "jwt"]
|
||||
categories:
|
||||
- 'java'
|
||||
- 'spring boot学习'
|
||||
- "java"
|
||||
- "spring boot学习"
|
||||
---
|
||||
|
||||
**本篇原创发布于:**[FleyX 的个人博客](http://tapme.top/blog/detail/2019-03-01-18-52)
|
||||
|
||||
**源码:**[github](https://github.com/FleyX/demo-project/tree/master/1.SSO%E5%8D%95%E7%82%B9%E7%99%BB%E5%BD%95)
|
||||
|
||||
照例配个图:
|
||||
![塞尔达,林克](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190301190816.png)
|
||||
|
||||
<div style="text-align:center;font-weight:400;font-size:0.9em">我叫林克,不是塞尔达</div>
|
||||
|
||||
  最近我们组要给负责的一个管理系统 A 集成另外一个系统 B,为了让用户使用更加便捷,避免多个系统重复登录,希望能够达到这样的效果——用户只需登录一次就能够在这两个系统中进行操作。很明显这就是**单点登录(Single Sign-On)**达到的效果,正好可以明目张胆的学一波单点登录知识。
|
||||
|
||||
本篇主要内容如下:
|
||||
@ -143,4 +136,6 @@ SSO 说:好嘞,这个地址是合法的可以送 jwt 过去,这就跳转
|
||||
|
||||
可以看到,在系统 A 登录系统后,系统 B,系统 C 都不再需要输入用户名密码进行登录。如果速度足够快甚至都注意不到调到 SSO 再跳回来的过程。
|
||||
|
||||
  如果有什么问题,可以在下方留言,或者邮件给我。看到都会回复的。
|
||||
**源码:**[github](https://github.com/FleyX/demo-project/tree/master/1.SSO%E5%8D%95%E7%82%B9%E7%99%BB%E5%BD%95)
|
||||
|
||||
**本篇原创发布于:**[www.tapme.top/blog/detail/2019-03-01-18-52](https://www.tapme.top/blog/detail/2019-03-01-18-52)
|
||||
|
@ -13,6 +13,7 @@ categories:
|
||||
最近在开发中用到了 java 的线程池,然后就很疑惑这个线程池到底要不要手动关闭,感觉是要关闭的,但是没人强调线程池用完要关闭。so 今天来试验下到底线程池用完要不要关闭。
|
||||
|
||||
**为避免引起误解被喷,特此说明下:下面的代码是为了验证 gc 在回收线程池对象时,线程池对象管理的线程是否会销毁掉。如下在循环中创建线程池是为了模拟线程池使用一次后不再使用的情况。
|
||||
|
||||
虽然通常线程池都是作为全局变量使用,但是如果作为局部变量使用呢?使用完要不要手动关闭掉?**
|
||||
|
||||
<!-- more -->
|
||||
|
@ -1,15 +1,13 @@
|
||||
---
|
||||
id: '2019-04-08-20-52'
|
||||
date: '2019/04/08 20:52'
|
||||
title: '最全java多线程总结1--线程基础'
|
||||
tags: ['java', 'thread']
|
||||
id: "2019-04-08-20-52"
|
||||
date: "2019/04/08 20:52"
|
||||
title: "最全java多线程学习总结1--线程基础"
|
||||
tags: ["java", "thread"]
|
||||
categories:
|
||||
- 'java'
|
||||
- 'java基础'
|
||||
- "java"
|
||||
- "java基础"
|
||||
---
|
||||
|
||||
本篇所用全部代码:[github](https://github.com/FleyX/demo-project/tree/master/2.javaThreadDemo)
|
||||
|
||||
  《java 核心技术》这本书真的不错,知识点很全面,翻译质量也还不错,本系列博文是对该书中并发章节的一个总结。
|
||||
|
||||
# 什么是线程
|
||||
@ -110,7 +108,7 @@ public class CustomThreadImplementInterface implements Runnable {
|
||||
|
||||
  通过查看 Thread 源码可以看到 Thread 类也是 Runnable 接口的一个实现类。
|
||||
|
||||
**PS:的代码全部使用 runnable 创建线程**
|
||||
**PS:后续代码全部使用 runnable 创建线程**
|
||||
|
||||
# 线程状态
|
||||
|
||||
@ -164,7 +162,7 @@ public class CustomThreadImplementInterface implements Runnable {
|
||||
|
||||
## 守护线程
|
||||
|
||||
  通过调用`Thread.setDaemon(true)`将一个线程转换为守护线程。守护线程唯一的用户是为其他线程提供服务,比如计时线程,定时发送计时信号给其他线程。因此当虚拟机中只有守护线程时,虚拟机就会关闭推出。**不要在守护线程中访问任何资源,比如文件、数据库等**
|
||||
  通过调用`Thread.setDaemon(true)`将一个线程转换为守护线程。守护线程唯一的用户是为其他线程提供服务,比如计时线程,定时发送计时信号给其他线程。因此当虚拟机中只有守护线程时,虚拟机就会关闭退出。**不要在守护线程中访问任何资源,处理任何业务逻辑**
|
||||
|
||||
## 未捕获异常处理器
|
||||
|
||||
@ -192,4 +190,6 @@ public class CustomExceptionHandler implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
  如果不设置默认处理器且不为独立的线程设置处理器,那么该线程的处理器就为该线程的线程组对象--ThreadGroup(因为线程组对象实现了`Thread.UncaughtExceptionHandler`接口)。
|
||||
|
||||
本篇所用全部代码:[github](https://github.com/FleyX/demo-project/tree/master/2.javaThreadDemo)
|
||||
|
||||
**本篇原创发布于:**[https://www.tapme.top/blog/detail/2019-04-08-20-52](https://www.tapme.top/blog/detail/2019-04-08-20-52)
|
||||
|
@ -1,15 +1,13 @@
|
||||
---
|
||||
id: '2019-04-10-20-52'
|
||||
date: '2019/04/10 20:52'
|
||||
title: '最全java多线程总结2--如何进行线程同步'
|
||||
tags: ['java', 'thread', 'lock', 'condition', 'synchronized']
|
||||
id: "2019-04-10-20-52"
|
||||
date: "2019/04/10 20:52"
|
||||
title: "最全java多线程总结2--如何进行线程同步"
|
||||
tags: ["java", "thread", "lock", "condition", "synchronized"]
|
||||
categories:
|
||||
- 'java'
|
||||
- 'java基础'
|
||||
- "java"
|
||||
- "java基础"
|
||||
---
|
||||
|
||||
本篇所用全部代码:[github](https://github.com/FleyX/demo-project/tree/master/2.javaThreadDemo)
|
||||
|
||||
  上篇对线程的一些基础知识做了总结,本篇来对多线程编程中最重要,也是最麻烦的一个部分——**同步**,来做个总结。
|
||||
|
||||
  创建线程并不难,难的是如何让多个线程能够良好的协作运行,大部分需要多线程处理的事情都不是完全独立的,大都涉及到数据的共享,本篇是对线程同步的一个总结,如有纰漏的地方,欢迎在评论中指出。
|
||||
@ -270,4 +268,6 @@ class Bank {
|
||||
- 如果能用 synchronized 的,尽量用它,这样既可以减少代码数量,减少出错的几率。
|
||||
- 如果上面都不能解决问题,那就只能使用 Lock/Condition 了。
|
||||
|
||||
本篇所用全部代码:[github](https://github.com/FleyX/demo-project/tree/master/2.javaThreadDemo)
|
||||
|
||||
**本文原创发布于:**[https://www.tapme.top/blog/detail/2019-04-10-20-52](https://www.tapme.top/blog/detail/2019-04-10-20-52)
|
||||
|
@ -1,14 +1,14 @@
|
||||
---
|
||||
id: '2019-04-11'
|
||||
date: '2019/04/11 00:00:00'
|
||||
title: '最全java多线程总结3——了解阻塞队列和线程安全集合不'
|
||||
tags: ['java', 'list', 'set', 'map']
|
||||
id: "2019-04-11"
|
||||
date: "2019/04/11 00:00:00"
|
||||
title: "最全java多线程总结3——了解阻塞队列和线程安全集合不"
|
||||
tags: ["java", "list", "set", "map"]
|
||||
categories:
|
||||
- 'java'
|
||||
- 'java基础'
|
||||
- "java"
|
||||
- "java基础"
|
||||
---
|
||||
|
||||
  看了前两篇你肯定已经理解了 java 并发编程的低层构建。然而,在实际编程中,应该经可能的远离低层结构,毕竟太底层的东西用起来是比较容易出错的,特别是并发编程,既难以调试,也难以发现问题,我们还是使用由并发处理的专业人员实现的较高层次的结构要方便、安全得多。
|
||||
  看了前两篇你肯定已经理解了 java 并发编程的底层构建。然而,在实际编程中,应该经可能的远离底层结构,毕竟太底层的东西用起来是比较容易出错的,特别是并发编程,既难以调试,也难以发现问题,我们还是使用由并发处理的专业人员实现的较高层次的结构要方便、安全得多。
|
||||
|
||||
# 阻塞队列
|
||||
|
||||
|
BIN
二维码推广图.png
BIN
二维码推广图.png
Binary file not shown.
Before Width: | Height: | Size: 76 KiB |
22
前端/react/react实战/1.react实战_聊天室-总览.md
Normal file
22
前端/react/react实战/1.react实战_聊天室-总览.md
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
id: "20190625"
|
||||
date: 2019/06/25 10:58:00
|
||||
title: "react实战之聊天室-1(总览)"
|
||||
tags: ["react", "antd", "table"]
|
||||
categories:
|
||||
- "前端"
|
||||
- "react"
|
||||
---
|
||||
|
||||
一个合格的全栈开发怎么能不会 react 呢?所以从现在开始系统的学习 react 开发。目标:完成完成一个简易的多人聊天室,包含前后台。
|
||||
|
||||
基于`create-react-app`进行开发,选择这个有以下两个原因:
|
||||
|
||||
- 从头开始配置 webpack 太复杂,不用了解的这么细致。
|
||||
- 也不使用`antd pro`,`umi.js`这类开箱即用的,隐藏了太多细节,也不考虑。
|
||||
|
||||
<!-- more -->
|
||||
|
||||
在学习过程中产生了如下的笔记:
|
||||
|
||||
- [1.react 环境搭建](https://www.tapme.top/blog/detail/20190626)
|
471
前端/react/react实战/2.react实战之多人聊天室-react环境搭建.md
Normal file
471
前端/react/react实战/2.react实战之多人聊天室-react环境搭建.md
Normal file
@ -0,0 +1,471 @@
|
||||
---
|
||||
id: "20190626"
|
||||
date: 2019/06/26 10:58:00
|
||||
title: "2.react实战之多人聊天室-react环境搭建"
|
||||
tags: ["react", "antd", "less", "create-react-web"]
|
||||
categories:
|
||||
- "前端"
|
||||
- "react"
|
||||
---
|
||||
|
||||
总集篇:[react 实战之多人聊天室](https://www.tapme.top/blog/detail/20190625)
|
||||
|
||||
本篇是实战系列的第一篇,主要是搭建 react 开发环境,在`create-react-app`的基础上加上如下功能:
|
||||
|
||||
- 按需引入 antd 组件库,支持主题定制
|
||||
- 支持 less 语法,并使用 css-module 形式 css
|
||||
- 支持路由
|
||||
- 支持 http 请求
|
||||
- 支持 redux
|
||||
|
||||
**注意**:需要 node 版本大于 8.0.
|
||||
|
||||
## 创建 create-react-app
|
||||
|
||||
1. 安装
|
||||
|
||||
```bash
|
||||
npm install -g create-react-app
|
||||
```
|
||||
|
||||
2. 创建 react 应用
|
||||
|
||||
```bash
|
||||
create-react-app chat-room
|
||||
```
|
||||
|
||||
<!-- more -->
|
||||
|
||||
生成的目录结构如下图所示:
|
||||
|
||||
![目录结构](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190625160702.png)
|
||||
|
||||
## 配置 antd,less
|
||||
|
||||
有两种方法能够对其配置进行修改:
|
||||
|
||||
- 通过`npm run eject`暴露出配置文件,进行配置修改,相比于下面的方法不太优雅,因此不考虑.
|
||||
- 通过`react-app-rewired`覆盖配置.
|
||||
|
||||
### 首先安装依赖
|
||||
|
||||
在 2.1.x 版本的 react-app-rewired 需要配合`customize-cra`来进行配置覆盖。所以需要安装如下依赖:
|
||||
|
||||
- react-app-rewired ,配置覆盖
|
||||
- customize-cra ,配置覆盖
|
||||
- antd ,ui 库
|
||||
- babel-plugin-import ,按需引入 antd
|
||||
- less ,less 支持
|
||||
- less-loader ,less 支持
|
||||
|
||||
代码如下:
|
||||
|
||||
```bash
|
||||
npm install --save react-app-rewired customize-cra antd babel-plugin-import less less-loader
|
||||
```
|
||||
|
||||
### 修改 package.json
|
||||
|
||||
用`react-app-rewired`替换掉原来的`react-scripts`
|
||||
|
||||
```json
|
||||
/* package.json */
|
||||
"scripts": {
|
||||
- "start": "react-scripts start",
|
||||
+ "start": "react-app-rewired start",
|
||||
- "build": "react-scripts build",
|
||||
+ "build": "react-app-rewired build",
|
||||
- "test": "react-scripts test",
|
||||
+ "test": "react-app-rewired test",
|
||||
}
|
||||
```
|
||||
|
||||
### 创建 config-overrides.js
|
||||
|
||||
在项目根目录,也就是`package.json`的同级目录创建`config-overrides.js`文件.内容如下:
|
||||
|
||||
```javascript
|
||||
const { override, fixBabelImports, addLessLoader } = require("customize-cra");
|
||||
|
||||
module.exports = override(
|
||||
fixBabelImports("import", {
|
||||
libraryName: "antd",
|
||||
libraryDirectory: "es",
|
||||
style: true
|
||||
}),
|
||||
addLessLoader({
|
||||
localIdentName: "[local]--[hash:base64:5]",
|
||||
javascriptEnabled: true,
|
||||
modifyVars: { "@primary-color": "#1DA57A" }
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
### 使用 css-module
|
||||
|
||||
要使用 css-module 需要将 css 文件命名为`fileName.module.less`,然后就能在组件中引入了,如下:
|
||||
|
||||
```javascript
|
||||
import React, { Component } from "react";
|
||||
import { Button } from "antd";
|
||||
import styles1 from "./index.module.less";
|
||||
|
||||
class Hello extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className={styles1.main}>
|
||||
hello
|
||||
<div className={styles1.text}>world</div>
|
||||
<Button type="primary">你好</Button>
|
||||
<div className="text1">heihei</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Hello;
|
||||
```
|
||||
|
||||
## 配置路由
|
||||
|
||||
首先修改 src 目录结构。改成如下所示:
|
||||
|
||||
![目录结构](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190627115439.png)
|
||||
|
||||
目录解释:
|
||||
|
||||
- assets: 存放图标,小图片等资源文件
|
||||
- components:存放公共组件
|
||||
- layout: 存放样式组件,用于嵌套路由和子路由中复用代码
|
||||
- pages: 存放页面组件
|
||||
- redux:存放 redux 相关
|
||||
- action: 存放 action
|
||||
- reducer: 存放 reducer 操作
|
||||
- util: 工具类
|
||||
|
||||
删除`serviceWorker.js`文件,并在`index.js`中删除和它相管的代码。这个是和离线使用相关的。
|
||||
|
||||
然后安装`react-router`依赖:
|
||||
|
||||
```bash
|
||||
cnpm install --save react-router-dom
|
||||
```
|
||||
|
||||
从路由开始就能体会到 react 一切都是 js 的精髓,react-router-dom 提供了一些路由组件来进行路由操作。本程序使用`history`路由。
|
||||
|
||||
首先修改`index.js`根组件放到`<BrowserRouter>`下,以开启 history 路由。代码如下:
|
||||
|
||||
```javascript
|
||||
// index.js
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import "./index.css";
|
||||
import App from "./App";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
|
||||
const s = (
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
ReactDOM.render(s, document.getElementById("root"));
|
||||
```
|
||||
|
||||
然后路由的配置方式有很多种,这里采用代码的方式组织路由,并将将 App.jsx 作为路由配置中心。
|
||||
|
||||
先加入登录和主页的路由,主要代码如下:
|
||||
|
||||
```javascript
|
||||
|
||||
render() {
|
||||
const mainStyle = {
|
||||
fontSize: "0.16rem"
|
||||
};
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<div className="fullScreen" style={mainStyle}>
|
||||
<Switch>
|
||||
<Route exact path="/" component={Main} />
|
||||
<Route exact path="/public/login" component={Login} />
|
||||
<Route exact path="/404" component={NotFound} />
|
||||
{/* 当前面的路由都匹配不到时就会重定向到/404 */}
|
||||
<Redirect path="/" to="/404" />
|
||||
</Switch>
|
||||
</div>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
名词解释:
|
||||
|
||||
- Switch: 该组件表示只匹配一个,匹配到后不再继续往下匹配
|
||||
- Route:路由组件
|
||||
- exact:表示完全匹配,如果开启这个,`/`只匹配`/`,否则匹配所有的路径
|
||||
- Redirect:重定向组件,当前面的都不匹配就会匹配这个(因为没有开启`exact`且 path 为`/`),然后重定向到`/404`
|
||||
|
||||
后续用到嵌套路由时会更加深入的讲解路由相关。
|
||||
|
||||
## 配置 http 请求工具
|
||||
|
||||
http 请求工具这里选择的是`axios`。
|
||||
|
||||
首先安装依赖:
|
||||
|
||||
```bash
|
||||
cnpm install --save axios
|
||||
```
|
||||
|
||||
然后编写工具类`util/httpUtil.js`,代码如下:
|
||||
|
||||
```javascript
|
||||
// httpUtil.js
|
||||
|
||||
import { notification } from "antd";
|
||||
import axios from "axios";
|
||||
|
||||
//定义http实例
|
||||
const instance = axios.create({
|
||||
// baseURL: "http://ali.tapme.top:8081/mock/16/chat/api/",
|
||||
headers: {
|
||||
token: window.token
|
||||
}
|
||||
});
|
||||
|
||||
//实例添加拦截器
|
||||
instance.interceptors.response.use(
|
||||
function(res) {
|
||||
return res.data;
|
||||
},
|
||||
function(error) {
|
||||
console.log(error);
|
||||
let message, description;
|
||||
if (error.response === undefined) {
|
||||
message = "出问题啦";
|
||||
description = "你的网络有问题";
|
||||
} else {
|
||||
message = "出问题啦:" + error.response.status;
|
||||
description = JSON.stringify(error.response.data);
|
||||
//401跳转到登录页面
|
||||
}
|
||||
notification.open({
|
||||
message,
|
||||
description,
|
||||
duration: 2
|
||||
});
|
||||
setTimeout(() => {
|
||||
if (error.response && error.response.status === 401) {
|
||||
let redirect = encodeURIComponent(window.location.pathname + window.location.search);
|
||||
window.location.replace("/public/login?redirect=" + redirect);
|
||||
}
|
||||
}, 1000);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default instance;
|
||||
```
|
||||
|
||||
主要实现了如下功能:
|
||||
|
||||
- 自动添加 token,设计前后端通过 jwt 做认证,因此每个请求都要加上 token
|
||||
- 响应预处理,如果有错误,自动弹窗提示。如果响应码为 401,重定向到登录页面。
|
||||
|
||||
## 配置 redux
|
||||
|
||||
redux 算是 react 的一大难点。这里我们可以把 redux 理解成一个内存数据库,用一个对象来存储所有的数据.
|
||||
|
||||
对这个数据的修改有着严格的限制,必须通过 reducer 来修改数据,通过 action 定义修改的动作。
|
||||
|
||||
这里以用户登录数据为例。
|
||||
|
||||
### 定义
|
||||
|
||||
1. 首先定义 action,创建文件`redux/action/loginInfoAction.js`,代码如下:
|
||||
|
||||
```javascript
|
||||
// 定义登录信息在store中的名字
|
||||
export const DATA_NAME = "loginInfo";
|
||||
|
||||
//定义修改loginInfo type
|
||||
export const CHANGE_LOGIN_INFO = "changeLoginStatus";
|
||||
|
||||
export const changeLoginInfo = (token, userInfo) => {
|
||||
return {
|
||||
type: CHANGE_LOGIN_INFO,
|
||||
data: {
|
||||
token,
|
||||
userInfo
|
||||
}
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
- CHANGE_LOGIN_INFO :定义操作类别
|
||||
- changeLoginInfo: 定义一个 action,在组件中调用,传入要修改的数据,在这里加上 type 上传递到 reducer 中处理.
|
||||
|
||||
2. 定义 reducer,创建文件`redux/reducer/loginInfo.js`,代码如下:
|
||||
|
||||
```javascript
|
||||
import * as loginAction from "../action/loginInfoAction";
|
||||
|
||||
function getInitData() {
|
||||
let token, userInfo;
|
||||
try {
|
||||
token = localStorage.getItem("token");
|
||||
userInfo = JSON.parse(localStorage.getItem("userInfo"));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
token = null;
|
||||
userInfo = null;
|
||||
}
|
||||
window.token = token;
|
||||
window.userInfo = userInfo;
|
||||
return {
|
||||
token,
|
||||
userInfo
|
||||
};
|
||||
}
|
||||
|
||||
const LoginStatusReducer = (state = getInitData(), action) => {
|
||||
switch (action.type) {
|
||||
case loginAction.CHANGE_LOGIN_INFO:
|
||||
return { ...action.data };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default LoginStatusReducer;
|
||||
```
|
||||
|
||||
- getInitData 方法用于初始化 userInfo 数据,这里写的比较复杂,会先从 localeStore 中取数据,然后挂载到 window 中,方便`httpUtil`中获取 token。
|
||||
- LoginStatusReducer 方法用于处理 action 中的数据,输出处理后的 loginInfo 数据。
|
||||
|
||||
3. 编写 reducer 汇总类(redux/reducer/index.js),所有 reducer 都要汇总到一个方法中,这样就能生成整个系统的 store 对象。代码如下:
|
||||
|
||||
```javascript
|
||||
import { combineReducers } from "redux";
|
||||
import { DATA_NAME } from "../action/loginInfoAction";
|
||||
import loginInfo from "./loginInfo";
|
||||
|
||||
const data = {};
|
||||
data[DATA_NAME] = loginInfo;
|
||||
|
||||
const reducer = combineReducers(data);
|
||||
|
||||
export default reducer;
|
||||
```
|
||||
|
||||
4. 编写`redux/index.js`,这里生成真正的数据对象,代码如下:
|
||||
|
||||
```javascript
|
||||
import { createStore } from "redux";
|
||||
import reducer from "./reducer";
|
||||
|
||||
const store = createStore(reducer);
|
||||
|
||||
export default store;
|
||||
```
|
||||
|
||||
5. 最后将 store 绑定到根节点(App.js)中即可,修改部分如下:
|
||||
|
||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190627165936.png)
|
||||
|
||||
![](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190627170032.png)
|
||||
|
||||
### 使用
|
||||
|
||||
这里以登录页为例,学习如何获取到 loginInfo 和修改 loginInfo.
|
||||
|
||||
1. 创建登录页组件,`pages/public/Login/index.js`
|
||||
登录页代码如下:
|
||||
|
||||
```javascript
|
||||
import React, { Component } from "react";
|
||||
import queryString from "query-string";
|
||||
import { Button, Input, message } from "antd";
|
||||
import IconFont from "../../../components/IconFont";
|
||||
import styles from "./index.module.less";
|
||||
import { connect } from "react-redux";
|
||||
import { changeLoginInfo, DATA_NAME } from "../../../redux/action/loginInfoAction";
|
||||
import axios from "../../../util/httpUtil";
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return state[DATA_NAME];
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
updateLoginInfo: (token, userInfo) => dispatch(changeLoginInfo(token, userInfo))
|
||||
};
|
||||
}
|
||||
|
||||
class Login extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
username: "",
|
||||
password: ""
|
||||
};
|
||||
this.query = queryString.parse(window.location.search);
|
||||
}
|
||||
|
||||
usernameInput = e => {
|
||||
this.setState({ username: e.target.value });
|
||||
};
|
||||
passwordInput = e => {
|
||||
this.setState({ password: e.target.value });
|
||||
};
|
||||
|
||||
submit = () => {
|
||||
axios.post("/public/login", this.state).then(res => {
|
||||
localStorage.setItem("token", res.token);
|
||||
localStorage.setItem("userInfo", JSON.stringify(res.userInfo));
|
||||
window.token = res.token;
|
||||
window.userInfo = res.userInfo;
|
||||
message.success("登录成功");
|
||||
this.props.updateLoginInfo(res.token, res.userInfo);
|
||||
if (this.query.redirect) {
|
||||
this.props.history.replace(decodeURIComponent(this.query.redirect));
|
||||
} else {
|
||||
this.props.history.replace("/");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="fullScreen flex main-center across-center">
|
||||
// 省略其他部分
|
||||
<Button type="primary" onClick={this.submit}>
|
||||
登录
|
||||
</Button>
|
||||
...
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Login);
|
||||
```
|
||||
|
||||
其中最关键的是下面三个部分:
|
||||
|
||||
- mapStateToProps:本方法从整个 store 中获取需要的数据,传递到 Login 组件的 props 中。
|
||||
- mapDispatchToProps:本方法用于修改 store 数据,返回的函数对象也会绑定到 Login 组件的 props 中,其中的 dispath 参数,用于调用 reducer 中的处理函数,根据 changeLoginInfo 返回的 action。
|
||||
- connect 方法用于将上面两个函数和 Login 组件绑定起来,这样就能在 props 中获取到了。**如果还有 withRouter**,应将 withRouter 放在最外层。
|
||||
|
||||
目前登录访问的接口为 yapi 的 mock 数据,真正的后台代码将会在后面编写。
|
||||
|
||||
## 结尾
|
||||
|
||||
作为一个刚开始学习 react 的菜鸟,欢迎各位大牛批评指正。
|
||||
|
||||
源码:[github](https://github.com/FleyX/ChatRoom),切换到 tag:`第一篇:环境搭建`,便可以看到截止到本篇的源码。
|
||||
|
||||
**本文原创发布于:**[www.tapme.top/blog/detail/20190626](http://www.tapme.top/blog/detail/20190626)
|
38
前端/react/react实战/3.react实战之多人聊天室-非核心功能实现.md
Normal file
38
前端/react/react实战/3.react实战之多人聊天室-非核心功能实现.md
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
id: "20190628"
|
||||
date: 2019/06/28 10:58:00
|
||||
title: "2.react实战之多人聊天室-登录、注册、重置密码功能前后端实现"
|
||||
tags: ["react", "antd", "less", "create-react-web"]
|
||||
categories:
|
||||
- "前端"
|
||||
- "react"
|
||||
---
|
||||
|
||||
总集篇:[react 实战之多人聊天室](https://www.tapme.top/blog/detail/20190625)
|
||||
|
||||
上一篇搭建了 reat 的环境,本篇正式开始编码了。先实现以下三个通用功能:
|
||||
|
||||
- 注册
|
||||
- 登录
|
||||
- 重置密码
|
||||
|
||||
鉴于本人设计水平有限(抠脚),所以这三个页面的风格将参考简书网页版。
|
||||
|
||||
# 模板编写
|
||||
|
||||
打开简书的注册页和登录页发现结构都是一样的,背景加上中间的输入框,如下图所示:
|
||||
|
||||
![简书登录页](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190629172621.png)
|
||||
|
||||
观察登录、注册两个页面的结构可以发现真正变化的部分只有中间的表单,所以我们可以将表单外的其他部分作为一个公共模板来编写。
|
||||
|
||||
创建`src/layout/LoginLayout`目录,然后在目录下建立`index.jsx`,`index.module.less`文件,如下图所示:
|
||||
|
||||
![创建登录模板](https://raw.githubusercontent.com/FleyX/files/master/blogImg/20190628192835.png)
|
||||
|
||||
index.jsx 代码如下:
|
||||
|
||||
```javascript
|
||||
```
|
||||
|
||||
# 注册功能实现
|
24
前端/react/其他/1.antd table 设置单元格单行显示.md
Normal file
24
前端/react/其他/1.antd table 设置单元格单行显示.md
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
id: "20190621"
|
||||
date: 2019/06/21 10:58:00
|
||||
title: "antd组件中table设置单行显示"
|
||||
tags: ["react", "antd", "table"]
|
||||
categories:
|
||||
- "前端"
|
||||
- "react"
|
||||
---
|
||||
|
||||
今天在开发中遇到了这样一个问题,antd 的 table 组件,在内容太多时会折行显示,如何才能让它不折行并且用省略号显示超出内容呢?
|
||||
|
||||
可以同给给单元格设置这样的 css 来达到效果:
|
||||
|
||||
```css
|
||||
/* 设置最大宽度,不能用width */
|
||||
max-width: 133px;
|
||||
/* 不折行 */
|
||||
white-space: nowrap;
|
||||
/* 超出部分隐藏 */
|
||||
overflow: hidden;
|
||||
/* 显示... */
|
||||
text-overflow: ellipsis;
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user