=null">_vue+spring开源门户博客网站源码">
赞
踩
码神之路网站所使用的博客,项目简单,需求明确,容易上手,非常适合做为练手级项目。
最终成品
项目讲解说明:
项目使用技术 :
springboot + mybatisplus+redis+mysql
代码地址:
个人博客代码地址
Spring常用注解,注解 IOC ,AOP,MVC 的理解
mybatisDao层 Mapper层 controller层 service层 model层 entity层 简介
mall商场学习文档
mybatisplus学习文档
mybatisplus配套代码
easycode搭配mybatisplus巨爽
@Autowired 的时候为什么注入接口不是实现类
@Service注解为什么是标注在实现类上的
mapper接口需要加注解吗?通过MapperScan减少注解
@Mapper与@MapperScan注解的作用是什么?
推荐安装插件
配好@Data使用
查看文章代码结构
自动提示编写的代码
快速生成xml文件
区分括号
vscode插件
前端的工程:
npm install
npm run build
npm run dev
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mszlu</groupId> <artifactId>blog-parent</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.0</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <!-- 排除 默认使用的logback --> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <!-- log4j2 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.2</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/joda-time/joda-time --> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.10.10</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
删除src文件
数据库配置
配置
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
使其打印到控制台
配置
mybatis-plus.global-config.db-config.table-prefix=ms_
代表标识下前缀是ms_,这样使其省略前缀,不用再定义前缀的表名
#server server.port= 8888 spring.application.name=mszlu_blog # datasource spring.datasource.url=jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=UTF-8&serverTimeZone=UTC spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #mybatis-plus mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl mybatis-plus.global-config.db-config.table-prefix=ms_ package com.mszlu.blog.config; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Author ljm * @Date 2021/10/10 20:11 * @Version 1.0 */ //让spring可以扫描到它 @Configuration //扫包,将此包下的接口生成代理实现类,并且注册到spring容器中 @MapperScan("com.mszlu.blog.dao.mapper") public class MybatisPlusConfig { //分页插件 //@Configuration可理解为用spring的时候xml里面的<beans>标签。 // @Bean可理解为用spring的时候xml里面的<bean>标签。 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; } } package com.mszlu.blog.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { //跨域配置,不可设置为*,不安全, 前后端分离项目,可能域名不一致 //本地测试 端口不一致 也算跨域 registry.addMapping("/**").allowedOrigins("http://localhost:8080"); } }
package com.mszlu.blog;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BlogApp {
public static void main(String[] args) {
SpringApplication.run(BlogApp.class,args);
}
}
接口url:/articles
请求方式:POST
请求参数:
参数名称
参数类型
说明
page
int
当前页数
pageSize
int
每页显示的数量
返回数据:
{ "success": true, "code": 200, "msg": "success", "data": [ { "id": 1, "title": "springboot介绍以及入门案例", "summary": "通过Spring Boot实现的服务,只需要依靠一个Java类,把它打包成jar,并通过`java -jar`命令就可以运行起来。 这一切相较于传统Spring应用来说,已经变得非常的轻便、简单。", "commentCounts": 2, "viewCounts": 54, "weight": 1, "createDate": "2609-06-26 15:58", "author": "12", "body": null, "tags": [ { "id": 5, "avatar": null, "tagName": "444" }, { "id": 7, "avatar": null, "tagName": "22" }, { "id": 8, "avatar": null, "tagName": "11" } ], "categorys": null }, { "id": 9, "title": "Vue.js 是什么", "summary": "Vue (读音 /vju?/,类似于 view) 是一套用于构建用户界面的渐进式框架。", "commentCounts": 0, "viewCounts": 3, "weight": 0, "createDate": "2609-06-27 11:25", "author": "12", "body": null, "tags": [ { "id": 7, "avatar": null, "tagName": "22" } ], "categorys": null }, { "id": 10, "title": "Element相关", "summary": "本节将介绍如何在项目中使用 Element。", "commentCounts": 0, "viewCounts": 3, "weight": 0, "createDate": "2609-06-27 11:25", "author": "12", "body": null, "tags": [ { "id": 5, "avatar": null, "tagName": "444" }, { "id": 6, "avatar": null, "tagName": "33" }, { "id": 7, "avatar": null, "tagName": "22" }, { "id": 8, "avatar": null, "tagName": "11" } ], "categorys": null } ] }
文章表
CREATE TABLE `blog`.`ms_article` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`comment_counts` int(0) NULL DEFAULT NULL COMMENT '评论数量',
`create_date` bigint(0) NULL DEFAULT NULL COMMENT '创建时间',
`summary` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '简介',
`title` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '标题',
`view_counts` int(0) NULL DEFAULT NULL COMMENT '浏览数量',
`weight` int(0) NOT NULL COMMENT '是否置顶',
`author_id` bigint(0) NULL DEFAULT NULL COMMENT '作者id',
`body_id` bigint(0) NULL DEFAULT NULL COMMENT '内容id',
`category_id` int(0) NULL DEFAULT NULL COMMENT '类别id',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
标签表
id,文章id,标签id,通过文章id可以间接查到标签id
CREATE TABLE `blog`.`ms_tag` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`article_id` bigint(0) NOT NULL,
`tag_id` bigint(0) NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `article_id`(`article_id`) USING BTREE,
INDEX `tag_id`(`tag_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
用户表
CREATE TABLE `blog`.`ms_sys_user` ( `id` bigint(0) NOT NULL AUTO_INCREMENT, `account` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '账号', `admin` bit(1) NULL DEFAULT NULL COMMENT '是否管理员', `avatar` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像', `create_date` bigint(0) NULL DEFAULT NULL COMMENT '注册时间', `deleted` bit(1) NULL DEFAULT NULL COMMENT '是否删除', `email` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱', `last_login` bigint(0) NULL DEFAULT NULL COMMENT '最后登录时间', `mobile_phone_number` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号', `nickname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称', `password` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码', `salt` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '加密盐', `status` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '状态', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
别名: model层 ,domain层
用途: 实体层,用于存放我们的实体类,与数据库中的属性值基本保持一致,实现set和get的方法。
例子:user表的实体User
文章
package com.mszlu.blog.dao.pojo; import lombok.Data; @Data public class Article { public static final int Article_TOP = 1; public static final int Article_Common = 0; private Long id; private String title; private String summary; private int commentCounts; private int viewCounts; /** * 作者id */ private Long authorId; /** * 内容id */ private Long bodyId; /** *类别id */ private Long categoryId; /** * 置顶 */ private int weight = Article_Common; /** * 创建时间 */ private Long createDate; }
用户
package com.mszlu.blog.dao.pojo; import lombok.Data; @Data public class SysUser { private Long id; private String account; private Integer admin; private String avatar; private Long createDate; private Integer deleted; private String email; private Long lastLogin; private String mobilePhoneNumber; private String nickname; private String password; private String salt; private String status; }
标签
package com.mszlu.blog.dao.pojo;
import lombok.Data;
@Data
public class Tag {
private Long id;
private String avatar;
private String tagName;
}
controller层。控制器,导入service层,因为service中的方法是我们使用到的,controller通过接收前端传过来的参数进行业务操作,在返回一个指定的路径或者数据表
package com.mszlu.blog.api; import com.mszlu.blog.dao.pojo.Article; import com.mszlu.blog.service.ArticleService; import com.mszlu.blog.vo.Archive; import com.mszlu.blog.vo.ArticleVo; import com.mszlu.blog.vo.Result; import com.mszlu.blog.vo.params.PageParams; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("articles") public class ArticleController { @Autowired private ArticleService articleService; //Result是统一结果返回 @PostMapping public Result articles(@RequestBody PageParams pageParams) { //ArticleVo 页面接收的数据 List<ArticleVo> articles = articleService.listArticlesPage(pageParams); return Result.success(articles); } }
统一最后的结果
package com.mszlu.blog.vo; import com.mszlu.blog.dao.pojo.Article; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @AllArgsConstructor @NoArgsConstructor public class Result { private boolean success; private Integer code; private String msg; private Object data; public static Result success(Object data) { return new Result(true,200,"success",data); } public static Result fail(Integer code, String msg) { return new Result(false,code,msg,null); } }
建立与前端交互的Vo文件
package com.mszlu.blog.vo; import com.mszlu.blog.dao.pojo.ArticleBody; import com.mszlu.blog.dao.pojo.Category; import com.mszlu.blog.dao.pojo.SysUser; import com.mszlu.blog.dao.pojo.Tag; import lombok.Data; import java.util.List; @Data public class ArticleVo { private Long id; private String title; private String summary; private int commentCounts; private int viewCounts; private int weight; /** * 创建时间 */ private String createDate; private String author; private ArticleBodyVo body; private List<TagVo> tags; private List<CategoryVo> categorys; }
service层主要是写业务逻辑方法,service层经常要调用dao层(也叫mapper层)的方法对数据进行增删改查的操作。*
建立service接口
package com.mszlu.blog.service; import com.mszlu.blog.vo.Archive; import com.mszlu.blog.vo.ArticleVo; import com.mszlu.blog.vo.params.PageParams; import java.util.List; public interface ArticleService { /** * 分页查询文章列表 * @param pageParams * @return */ Result listArticle(PageParams pageParams); }
建立service接口的实现类
package com.mszlu.blog.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.mszlu.blog.dao.ArticleMapper; import com.mszlu.blog.dao.SysUserMapper; import com.mszlu.blog.dao.pojo.Article; import com.mszlu.blog.dao.pojo.SysUser; import com.mszlu.blog.dao.pojo.Tag; import com.mszlu.blog.service.ArticleService; import com.mszlu.blog.service.SysUserService; import com.mszlu.blog.service.TagsService; import com.mszlu.blog.vo.ArticleBodyVo; import com.mszlu.blog.vo.ArticleVo; import com.mszlu.blog.vo.TagVo; import com.mszlu.blog.vo.params.PageParams; import org.joda.time.DateTime; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; @Service public class ArticleServiceImpl implements ArticleService { @Autowired private ArticleMapper articleMapper; @Autowired private TagService tagService; @Autowired private SysUserService sysUserService; @Override public Result listArticle(PageParams pageParams) { /** * 1、分页查询article数据库表 */ Page<Article> page = new Page<>(pageParams.getPage(), pageParams.getPageSize()); LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>(); //是否置顶进行排序, //时间倒序进行排列相当于order by create_data desc queryWrapper.orderByDesc(Article::getWeight,Article::getCreateDate); Page<Article> articlePage = articleMapper.selectPage(page, queryWrapper); //分页查询用法 https://blog.csdn.net/weixin_41010294/article/details/105726879 List<Article> records = articlePage.getRecords(); // 要返回我们定义的vo数据,就是对应的前端数据,不应该只返回现在的数据需要进一步进行处理 List<ArticleVo> articleVoList =copyList(records,true,true); return Result.success(articleVoList); } private List<ArticleVo> copyList(List<Article> records,boolean isTag,boolean isAuthor) { List<ArticleVo> articleVoList = new ArrayList<>(); for (Article record : records) { articleVoList.add(copy(record,isTag,isAuthor)); } return articleVoList; } //"eop的作用是对应copyList,集合之间的copy分解成集合元素之间的copy private ArticleVo copy(Article article,boolean isTag,boolean isAuthor){ ArticleVo articleVo = new ArticleVo(); //BeanUtils.copyProperties用法 https://blog.csdn.net/Mr_linjw/article/details/50236279 BeanUtils.copyProperties(article, articleVo); articleVo.setCreateDate(new DateTime(article.getCreateDate()).toString("yyyy-MM-dd HH:mm")); //并不是所有的接口都需要标签和作者信息 if(isTag){ Long articleId = article.getId(); articleVo.setTags(tagService.findTagsByArticleId(articleId)); } if (isAuthor) { //拿到作者id Long authorId = article.getAuthorId(); articleVo.setAuthor(sysUserService.findUserById(authorId).getNickname()); } return articleVo; } }
建立用户的service接口
package com.mszlu.blog.service;
import com.mszlu.blog.dao.pojo.SysUser;
public interface UserService {
SysUser findUserById(Long userId);
}
建立用户的service接口实现类
package com.mszlu.blog.service.impl; import com.mszlu.blog.dao.SysUserMapper; import com.mszlu.blog.dao.pojo.SysUser; import com.mszlu.blog.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class SysUserServiceImpl implements SysUserService { @Autowired private SysUserMapper sysUserMapper; @Override public SysUser findUserById(Long id) { //根据id查询 //为防止sysUser为空增加一个判断 SysUser sysUser = sysUserMapper.selectById(id); if (sysUser == null){ sysUser = new SysUser(); sysUser.setNickname("码神之路"); } return sysUser; } }
TagMapper的建立中遇到这个问题了,办法是在建立到TagMapper后需要建立xml文件进行读写
xml文件放到resource文件夹下
文件夹名和xml文件名必须和TagMapper.java文件夹保持一致
使用IntelliJ IDEA创建多级文件夹时,文件夹名为com.immer.monitor.persistence 和 com/immer/monitor/persistence 均会显示为如下图所示
但实际结构确实截然不同 com.immer.monitor.persistence 是单个文件夹 而 com/immer/monitor/persistence 是一个文件夹嵌套
会导致资源文件not found 的问题,而且很难排查得到
要不会显示找不到文件夹路径的问题,因为我们要保证mapper.xml要和mapper的文件夹和路径保持一致
建立标签的service接口
package com.mszlu.blog.service;
import com.mszlu.blog.dao.pojo.Tag;
import com.mszlu.blog.vo.TagVo;
import java.util.List;
public interface TagsService {
List<TagVo> findTagsByArticleId(Long id);
}
建立tag的service接口的实现类
package com.mszlu.blog.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.mszlu.blog.dao.TagMapper; import com.mszlu.blog.dao.pojo.Tag; import com.mszlu.blog.service.TagsService; import com.mszlu.blog.vo.TagVo; import org.apache.commons.collections.CollectionUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @Service public class TagsServiceImpl implements TagsService { @Autowired private TagMapper tagMapper; /** * ms_article_tag是文章和标签的关联表 * ms_tag为单纯的标签的表 * @param articleId * @return */ @Override public List<TagVo> findTagsByArticleId(Long articleId) { //mybatisplus无法进行多表查询 List<Tag> tags = tagMapper.findTagsByArticleId(articleId); return copyList(tags); } private List<TagVo> copyList(List<Tag> tagList) { List<TagVo> tagVoList = new ArrayList<>(); for (Tag tag : tagList) { tagVoList.add(copy(tag)); } return tagVoList; } private TagVo copy(Tag tag) { TagVo tagVo = new TagVo(); BeanUtils.copyProperties(tag, tagVo); return tagVo; } }
mapper层=dao层,现在用mybatis逆向工程生成的mapper层,其实就是dao层。
dao层对数据库进行数据持久化操作,他的方法语句是直接针对数据库操作的,而service层是针对我们controller,也就是针对我们使用者。service的impl是把mapper和service进行整合的文件。
dao层和service层关系:service层经常要调用dao层的方法对数据进行增删改查的操作,现实开发中,对业务的操作会涉及到数据的操
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。