目录

系统展示

前端核心代码

后端代码

数据库设计

代码地址


系统展示

主页

登录页面

登录成功之后

发布博客

发布成功

点击编辑还可以对自己的文章进行编辑

前端核心代码

主页

<template><div class="mcontaner"><Header></Header><div class="block"><el-timeline><el-timeline-item :timestamp="blog.created" placement="top" v-for="blog in blogs"><el-card><h4><router-link :to="{name: 'BlogDetail', params: {blogId: blog.id}}">{{blog.title}}</router-link></h4><p>{{blog.description}}</p></el-card></el-timeline-item></el-timeline><el-pagination class="mpage"backgroundlayout="prev, pager, next":current-page="currentPage":page-size="pageSize":total="total"@current-change=page></el-pagination></div></div>
</template><script>import Header from "../components/Header";export default {name: "Blogs.vue",components: {Header},data() {return {blogs: {},currentPage: 1,total: 0,pageSize: 5}},methods: {page(currentPage) {const _this = this_this.$axios.get("/blogs?currentPage=" + currentPage).then(res => {console.log(res)_this.blogs = res.data.data.records_this.currentPage = res.data.data.current_this.total = res.data.data.total_this.pageSize = res.data.data.size})}},created() {this.page(1)}}
</script><style scoped>.mpage {margin: 0 auto;text-align: center;}</style>

博客编辑页

<template><div><Header></Header><div class="m-content"><el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"><el-form-item label="标题" prop="title"><el-input v-model="ruleForm.title"></el-input></el-form-item><el-form-item label="摘要" prop="description"><el-input type="textarea" v-model="ruleForm.description"></el-input></el-form-item><el-form-item label="内容" prop="content"><mavon-editor v-model="ruleForm.content"></mavon-editor></el-form-item><el-form-item><el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button><el-button @click="resetForm('ruleForm')">重置</el-button></el-form-item></el-form></div></div>
</template><script>import Header from "../components/Header";export default {name: "BlogEdit.vue",components: {Header},data() {return {ruleForm: {id: '',title: '',description: '',content: ''},rules: {title: [{ required: true, message: '请输入标题', trigger: 'blur' },{ min: 3, max: 25, message: '长度在 3 到 25 个字符', trigger: 'blur' }],description: [{ required: true, message: '请输入摘要', trigger: 'blur' }],content: [{ trequired: true, message: '请输入内容', trigger: 'blur' }]}};},methods: {submitForm(formName) {this.$refs[formName].validate((valid) => {if (valid) {const _this = thisthis.$axios.post('/blog/edit', this.ruleForm, {headers: {"Authorization": localStorage.getItem("token")}}).then(res => {console.log(res)_this.$alert('操作成功', '提示', {confirmButtonText: '确定',callback: action => {_this.$router.push("/blogs")}});})} else {console.log('error submit!!');return false;}});},resetForm(formName) {this.$refs[formName].resetFields();}},created() {const blogId = this.$route.params.blogIdconsole.log(blogId)const _this = thisif(blogId) {this.$axios.get('/blog/' + blogId).then(res => {const blog = res.data.data_this.ruleForm.id = blog.id_this.ruleForm.title = blog.title_this.ruleForm.description = blog.description_this.ruleForm.content = blog.content})}}}
</script><style scoped>.m-content {text-align: center;}
</style>

登录页面

<template><div><el-container><el-header><img class="mlogo" src="https://www.markerhub.com/dist/images/logo/markerhub-logo.png" alt=""></el-header><el-main><el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"><el-form-item label="用户名" prop="username"><el-input v-model="ruleForm.username"></el-input></el-form-item><el-form-item label="密码" prop="password"><el-input type="password" v-model="ruleForm.password"></el-input></el-form-item><el-form-item><el-button type="primary" @click="submitForm('ruleForm')">登录</el-button><el-button @click="resetForm('ruleForm')">重置</el-button><el-button ><el-link href="/blogs">主页</el-link></el-button></el-form-item></el-form></el-main></el-container></div>
</template><script>export default {name: "Login",data() {return {ruleForm: {username: 'sy',password: '111111'},rules: {username: [{ required: true, message: '请输入用户名', trigger: 'blur' },{ min: 0, max: 15, message: '长度在 3 到 15 个字符', trigger: 'blur' }],password: [{ required: true, message: '请选择密码', trigger: 'change' }]}};},methods: {submitForm(formName) {this.$refs[formName].validate((valid) => {if (valid) {const _this = thisthis.$axios.post('/login', this.ruleForm).then(res => {console.log(res.data)const jwt = res.headers['authorization']const userInfo = res.data.data// 把数据共享出去_this.$store.commit("SET_TOKEN", jwt)_this.$store.commit("SET_USERINFO", userInfo)// 获取console.log(_this.$store.getters.getUser)_this.$router.push("/blogs")})} else {console.log('error submit!!');return false;}});},resetForm(formName) {this.$refs[formName].resetFields();}}}
</script><style scoped>.el-header, .el-footer {background-color: #B3C0D1;color: #333;text-align: center;line-height: 60px;}.el-aside {background-color: #D3DCE6;color: #333;text-align: center;line-height: 200px;}.el-main {/*background-color: #E9EEF3;*/color: #333;text-align: center;line-height: 160px;}body > .el-container {margin-bottom: 40px;}.el-container:nth-child(5) .el-aside,.el-container:nth-child(6) .el-aside {line-height: 260px;}.el-container:nth-child(7) .el-aside {line-height: 320px;}.mlogo {height: 60%;margin-top: 10px;}.demo-ruleForm {max-width: 500px;margin: 0 auto;}</style>

博客详情页

<template><div><Header></Header><div class="mblog"><h2> {{ blog.title }}</h2><el-link icon="el-icon-edit" v-if="ownBlog"><router-link :to="{name: 'BlogEdit', params: {blogId: blog.id}}" >编辑</router-link></el-link><el-divider></el-divider><div class="markdown-body" v-html="blog.content"></div></div></div>
</template><script>import 'github-markdown-css'import Header from "../components/Header";export default {name: "BlogDetail.vue",components: {Header},data() {return {blog: {id: "",title: "",content: ""},ownBlog: false}},created() {const blogId = this.$route.params.blogIdconsole.log(blogId)const _this = thisthis.$axios.get('/blog/' + blogId).then(res => {const blog = res.data.data_this.blog.id = blog.id_this.blog.title = blog.titlevar MardownIt = require("markdown-it")var md = new MardownIt()var result = md.render(blog.content)_this.blog.content = result_this.ownBlog = (blog.userId === _this.$store.getters.getUser.id)})}}
</script><style scoped>.mblog {box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);width: 100%;min-height: 700px;padding: 20px 15px;}</style>

后端代码

博客接口

@RestController
public class BlogController {@AutowiredBlogService blogService;//    列表@GetMapping("/blogs")public Result list(@RequestParam(defaultValue = "1") Integer currentPage) {Page page = new Page(currentPage, 5);IPage pageData = blogService.page(page, new QueryWrapper<Blog>().orderByDesc("created"));return Result.succ(pageData);}//    详情@GetMapping("/blog/{id}")public Result detail(@PathVariable(name = "id") Long id) {Blog blog = blogService.getById(id);Assert.notNull(blog, "该博客已被删除");return Result.succ(blog);}//    编辑@RequiresAuthentication@PostMapping("/blog/edit")public Result edit(@Validated @RequestBody Blog blog) {//        Assert.isTrue(false, "公开版不能任意编辑!");Blog temp = null;if(blog.getId() != null) {temp = blogService.getById(blog.getId());// 只能编辑自己的文章System.out.println(ShiroUtil.getProfile().getId());Assert.isTrue(temp.getUserId().longValue() == ShiroUtil.getProfile().getId().longValue(), "没有权限编辑");} else {temp = new Blog();temp.setUserId(ShiroUtil.getProfile().getId());temp.setCreated(LocalDateTime.now());temp.setStatus(0);}BeanUtil.copyProperties(blog, temp, "id", "userId", "created", "status");blogService.saveOrUpdate(temp);return Result.succ(null);}}

用户校验接口

@RestController
public class AccountController {@AutowiredUserService userService;@AutowiredJwtUtils jwtUtils;@PostMapping("/login")public Result login(@Validated @RequestBody LoginDto loginDto, HttpServletResponse response) {System.out.println(loginDto.getUsername());User user = userService.getOne(new QueryWrapper<User>().eq("username", loginDto.getUsername()));System.out.println(2222);Assert.notNull(user, "用户不存在");if(!user.getPassword().equals(SecureUtil.md5(loginDto.getPassword()))){return Result.fail("密码不正确");}String jwt = jwtUtils.generateToken(user.getId());response.setHeader("Authorization", jwt);response.setHeader("Access-control-Expose-Headers", "Authorization");return Result.succ(MapUtil.builder().put("id", user.getId()).put("username", user.getUsername()).put("avatar", user.getAvatar()).put("email", user.getEmail()).map());}@RequiresAuthentication@GetMapping("/logout")public Result logout() {SecurityUtils.getSubject().logout();return Result.succ(null);}}

spring整合shiro

@Component
public class JwtFilter extends AuthenticatingFilter {@AutowiredJwtUtils jwtUtils;@Overrideprotected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {HttpServletRequest request = (HttpServletRequest) servletRequest;String jwt = request.getHeader("Authorization");if(StringUtils.isEmpty(jwt)) {return null;}return new JwtToken(jwt);}@Overrideprotected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {HttpServletRequest request = (HttpServletRequest) servletRequest;String jwt = request.getHeader("Authorization");if(StringUtils.isEmpty(jwt)) {return true;} else {// 校验jwtClaims claim = jwtUtils.getClaimByToken(jwt);if(claim == null || jwtUtils.isTokenExpired(claim.getExpiration())) {throw new ExpiredCredentialsException("token已失效,请重新登录");}// 执行登录return executeLogin(servletRequest, servletResponse);}}@Overrideprotected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {HttpServletResponse httpServletResponse = (HttpServletResponse) response;Throwable throwable = e.getCause() == null ? e : e.getCause();Result result = Result.fail(throwable.getMessage());String json = JSONUtil.toJsonStr(result);try {httpServletResponse.getWriter().print(json);} catch (IOException ioException) {}return false;}@Overrideprotected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {HttpServletRequest httpServletRequest = WebUtils.toHttp(request);HttpServletResponse httpServletResponse = WebUtils.toHttp(response);httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));// 跨域时会首先发送一个OPTIONS请求,这里我们给OPTIONS请求直接返回正常状态if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {httpServletResponse.setStatus(org.springframework.http.HttpStatus.OK.value());return false;}return super.preHandle(request, response);}}
@Configuration
public class ShiroConfig {@AutowiredJwtFilter jwtFilter;@Beanpublic SessionManager sessionManager(RedisSessionDAO redisSessionDAO) {DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();// inject redisSessionDAOsessionManager.setSessionDAO(redisSessionDAO);return sessionManager;}@Beanpublic DefaultWebSecurityManager securityManager(AccountRealm accountRealm,SessionManager sessionManager,RedisCacheManager redisCacheManager) {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(accountRealm);//inject sessionManagersecurityManager.setSessionManager(sessionManager);// inject redisCacheManagersecurityManager.setCacheManager(redisCacheManager);return securityManager;}@Beanpublic ShiroFilterChainDefinition shiroFilterChainDefinition() {DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();Map<String, String> filterMap = new LinkedHashMap<>();filterMap.put("/**", "jwt");chainDefinition.addPathDefinitions(filterMap);return chainDefinition;}@Bean("shiroFilterFactoryBean")public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager,ShiroFilterChainDefinition shiroFilterChainDefinition) {ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();shiroFilter.setSecurityManager(securityManager);Map<String, Filter> filters = new HashMap<>();filters.put("jwt", jwtFilter);shiroFilter.setFilters(filters);Map<String, String> filterMap = shiroFilterChainDefinition.getFilterChainMap();shiroFilter.setFilterChainDefinitionMap(filterMap);return shiroFilter;}}

数据库设计

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for m_blog
-- ----------------------------
DROP TABLE IF EXISTS `m_blog`;
CREATE TABLE `m_blog`  (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_id` bigint(20) NOT NULL,`title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,`description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,`content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,`created` datetime NOT NULL,`status` tinyint(4) NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;-- ----------------------------
-- Records of m_blog
-- ----------------------------
INSERT INTO `m_blog` VALUES (6, 2, '123', '321', '123213', '2022-12-20 12:14:56', 0);
INSERT INTO `m_blog` VALUES (7, 1, 'syy', '23', '12321321321', '2022-12-20 12:52:00', 0);
INSERT INTO `m_blog` VALUES (8, 1, '123213', '123213', 'ceshi', '2022-12-21 07:46:34', 0);
INSERT INTO `m_blog` VALUES (9, 1, '测试1', '测试二', '测试', '2022-12-29 04:20:06', 0);-- ----------------------------
-- Table structure for m_discussion
-- ----------------------------
DROP TABLE IF EXISTS `m_discussion`;
CREATE TABLE `m_discussion`  (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_id` bigint(20) NOT NULL,`title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,`description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,`content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,`created` datetime NOT NULL,`status` tinyint(4) NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;-- ----------------------------
-- Records of m_discussion
-- ----------------------------
INSERT INTO `m_discussion` VALUES (1, 1, '小明', '五行学习法很不错', '五行学习法很好', '2020-10-13 21:05:31', 0);
INSERT INTO `m_discussion` VALUES (6, 1, '小李', 'nice', '内容', '2022-11-21 15:25:15', 0);
INSERT INTO `m_discussion` VALUES (7, 1, '小张', '不错', '', '2022-11-21 16:15:57', 0);
INSERT INTO `m_discussion` VALUES (8, 1, '小伤', '挺好的', '', '2022-11-21 16:25:36', 0);
INSERT INTO `m_discussion` VALUES (9, 1, 'shangyi', '挺不错的', '', '2022-11-21 16:27:00', 0);
INSERT INTO `m_discussion` VALUES (10, 1, '小商', '很好', '', '2022-11-21 16:31:49', 0);
INSERT INTO `m_discussion` VALUES (11, 1, '小诗', '挺好的', '', '2022-11-21 16:34:11', 0);
INSERT INTO `m_discussion` VALUES (12, 1, '尚艺', '很好', '', '2022-11-25 16:55:35', 0);
INSERT INTO `m_discussion` VALUES (13, 1, '11', '11', '', '2022-12-09 14:19:00', 0);
INSERT INTO `m_discussion` VALUES (14, 1, '111', '111112', '', '2022-12-09 15:31:43', 0);
INSERT INTO `m_discussion` VALUES (15, 1, '小诺', '12三大', '', '2022-12-09 15:33:04', 0);
INSERT INTO `m_discussion` VALUES (16, 1, '12', '123', '', '2022-12-09 15:34:20', 0);
INSERT INTO `m_discussion` VALUES (17, 1, '111', '111', '', '2022-12-09 16:25:59', 0);
INSERT INTO `m_discussion` VALUES (18, 1, 'xiao', '123', '', '2022-12-09 16:59:00', 0);-- ----------------------------
-- Table structure for m_user
-- ----------------------------
DROP TABLE IF EXISTS `m_user`;
CREATE TABLE `m_user`  (`id` bigint(20) NOT NULL AUTO_INCREMENT,`username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`email` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`password` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`status` int(5) NOT NULL,`created` datetime NULL DEFAULT NULL,`last_login` datetime NULL DEFAULT NULL,`like` int(23) NULL DEFAULT NULL,`collection` int(11) NULL DEFAULT NULL,`visit` int(11) NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE,INDEX `UK_USERNAME`(`username`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;-- ----------------------------
-- Records of m_user
-- ----------------------------
INSERT INTO `m_user` VALUES (1, 'sy', 'https://image-1300566513.cos.ap-guangzhou.myqcloud.com/upload/images/5a9f48118166308daba8b6da7e466aab.jpg', NULL, '96e79218965eb72c92a549dd5a330112', 0, '2020-04-20 10:44:01', NULL, NULL, NULL, NULL);
INSERT INTO `m_user` VALUES (2, 'xia', NULL, NULL, '96e79218965eb72c92a549dd5a330112', 0, NULL, NULL, NULL, NULL, NULL);SET FOREIGN_KEY_CHECKS = 1;

代码地址

博客系统: 博客系统初态,可以发表文章,浏览文章

基于vue+spring的博客系统相关推荐

  1. 基于SpringBoot和Vue的个人博客系统

    基于SpringBoot和Vue的个人博客系统 前言 ​ 本期项目分享一个漫威主题的炫酷博客系统,基于SpringBoot和Vue开发的前端分离项目.博客系统分为博客前台和博客后台两部分,游客可以访问 ...

  2. 使用 ThinkJS + Vue.js 开发博客系统

    编者注:ThinkJS 作为一款 Node.js 高性能企业级 Web 框架,收到了越来越多的用户的喜爱.今天我们请来了 ThinkJS 用户 @lscho 同学为我们分享他基于 ThinkJS 开发 ...

  3. 基于python的个人博客系统的设计开题报告_基于SSM的个人博客系统设计开题报告...

    本 科 毕 业 设 计(论文)开 题 报 告 题  目:基于SSM的个人博客系统设计与实现 专题题目(若无专题则不填): 本课题来源及研究现状: 关于博客的未来:在创办了博客中国(blogchina) ...

  4. 基于ssm的个人博客系统的设计与实现(含源文件)

    欢迎添加微信互相交流学习哦! 项目源码:https://gitee.com/oklongmm/biye 进入二十一世纪,以Internet为核心的现代网络积水和通信技术已经得到了飞速的发展和广泛的应用 ...

  5. 【基于python+Django的博客系统-哔哩哔哩】 https://b23.tv/bmRfAMu

    [基于python+Django的博客系统-哔哩哔哩] https://b23.tv/bmRfAMu https://b23.tv/bmRfAMu

  6. 关于博客的论文php,基于php的个人博客系统毕业设计论文

    版权声明:以上文章中所选用的图片及文字来源于网络以及用户投稿,由于未联系到知识产权人或未发现有关知识产权的登记,如有知识产权人并不愿意我们使用,如果有侵权请立即联系:55525090@qq.com,我 ...

  7. 推荐一个基于Springboot+Vue的开源博客系统

    简介 这是一个基于Springboot2.x,vue2.x的前后端分离的开源博客系统,提供 前端界面+管理界面+后台服务 的整套系统源码.响应式设计,手机.平板.PC,都有良好的视觉效果! 你可以拿它 ...

  8. 基于SpringBoot + Vue的个人博客系统12——使用vue-admin-template展示文章列表(后台管理)

    简介 前面我们实现了博客系统的前台展示页面,还有留言功能没有实现,实现留言功能无非就是在后端增加留言表,对留言进行增删改查.和文章表类似,这里就不在赘述. 既然作为一款动态博客,那么后台管理是必不可少 ...

  9. java基于ssm的个人博客系统_一个基于 Spring Boot 的开源免费博客系统

    概况 mblog 开源免费的博客系统, Java 语言开发, 支持 mysql/h2 数据库, 采用 spring-boot.jpa.shiro.bootstrap 等流行框架开发.支持多用户, 支持 ...

  10. java基于ssm的个人博客系统_调研了 100 来个 Java 博客系统,发现这5个最好用

    大家好!我是 Guide 哥,Java 后端开发.一个会一点前端,喜欢烹饪的自由少年. 最近想倒腾一下博客,看了很多现成的比较成熟的开源博客系统,自己也简单从下面几个维度总结对比了一下: star数量 ...

最新文章

  1. python mysql批量insert数据、返回id_Python3 操作 MySQL 插入一条数据并返回主键 id的实例...
  2. 使用JavaScript变量需要注意哪些语法细节?
  3. 《松本行弘的程序世界》中文版原作者序
  4. 每日一博 - Spring Boot Application as a Service
  5. js三元运算符_这些优化技巧可以避免我们在 JS 中过多的使用 IF 语句
  6. Boost:boost::atomic用法实例
  7. 三个变量中怎么找出中间值_scratch图形化编程基础练习-变量交换
  8. CCF NOI1052 Self-Numbers
  9. python接口自动化 post请求,body 带headers参数
  10. 百度移动搜索主要有如下几类结果构成
  11. 适合完全初学者的Python自学路线图和学习方法
  12. mysql手册02_事务
  13. if判断和grep命令-w及搜索前后行
  14. Android——广播
  15. 详细阅读Spark论文
  16. verilog练习:hdlbits网站上的做题笔记(6)
  17. H+4.9响应式后台主题UI框架源码带完整文档-免费下载
  18. 人工智能在生物信号领域的应用——脑机接口
  19. 少儿C++快乐编程网络教程
  20. 快速提高数学成绩的奇书《巧学妙解王》高中数学!

热门文章

  1. 使用tsx开发vue项目入门
  2. 知识图谱中三元组抽取
  3. 外贸企业邮箱是什么?大连邮箱,邮件归档系统
  4. 智慧天气系统 - 可视化大屏(Echarts)管理系统(HTTP(S)协议)物联网平台(MQTT协议)
  5. 接力队选拔matlab,这是我见过的操作最好的接力队之一= =
  6. scipy中使用linalg.inv函数计算矩阵的逆矩阵
  7. 他曾被视为马斯克第二,现在是等着坐牢的骗子
  8. 记录使用git时出现Permission denied 问题的解决
  9. ES index 管理
  10. Beyond Part Models: Person Retrieval with Refined Part Pooling 阅读笔记