SpringBoot+Vue 豆宝社区前后端分离项目手把手实战系列教程 02---创建后端工程 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
songboriceboy
V2EX    程序员

SpringBoot+Vue 豆宝社区前后端分离项目手把手实战系列教程 02---创建后端工程

  •  
  •   songboriceboy 2021-02-19 22:05:24 +08:00 1513 次点击
    这是一个创建于 1702 天前的主题,其中的信息可能已经有所发展或是发生改变。

    豆宝社区项目实战教程简介

    本项目实战教程配有免费视频教程,配套代码完全开源。手把手从零开始搭建一个目前应用最广泛的 Springboot+Vue 前后端分离多用户社区项目。本项目难度适中,为便于大家学习,每一集视频教程对应在 Github 上的每一次提交。

    项目首页截图

    image

    代码开源地址

    前端 后端

    视频教程地址

    视频教程

    前端技术栈

    Vue Vuex Vue Router Axios Bulma Buefy Element Vditor DarkReader

    后端技术栈

    Spring Boot Mysql Mybatis MyBatis-Plus Spring Security JWT Lombok

    搭建后端工程

    0.导入 sql

    在数据库导入

    /* Navicat Premium Data Transfer Source Server : localhost Source Server Type : MySQL Source Server Version : 80022 Source Host : localhost:3306 Source Schema : doubao Target Server Type : MySQL Target Server Version : 80022 File Encoding : 65001 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for bms_billboard -- ---------------------------- DROP TABLE IF EXISTS `bms_billboard`; CREATE TABLE `bms_billboard` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', `content` varchar(255) CHARACTER SET utf8mb4 NOT NULL COMMENT '公告', `create_time` datetime NULL DEFAULT NULL COMMENT '公告时间', `show` tinyint(1) NULL DEFAULT NULL COMMENT '1:展示中,0:过期', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COMMENT = '全站公告' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of bms_billboard -- ---------------------------- INSERT INTO `bms_billboard` VALUES (2, 'R1.0 开始已实现护眼模式 ,妈妈再也不用担心我的眼睛了。', '2020-11-19 17:16:19', 0); INSERT INTO `bms_billboard` VALUES (4, '系统已更新至最新版 1.0.1', NULL, 1); -- ---------------------------- -- Table structure for bms_follow -- ---------------------------- DROP TABLE IF EXISTS `bms_follow`; CREATE TABLE `bms_follow` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', `parent_id` varchar(20) CHARACTER SET utf8mb4 NULL DEFAULT NULL COMMENT '被关注人 ID', `follower_id` varchar(20) CHARACTER SET utf8mb4 NULL DEFAULT NULL COMMENT '关注人 ID', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 130 CHARACTER SET = utf8mb4 COMMENT = '用户关注' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of bms_follow -- ---------------------------- INSERT INTO `bms_follow` VALUES (65, '1329723594994229250', '1317498859501797378'); INSERT INTO `bms_follow` VALUES (85, '1332912847614083073', '1332636310897664002'); INSERT INTO `bms_follow` VALUES (129, '1349290158897311745', '1349618748226658305'); -- ---------------------------- -- Table structure for bms_post -- ---------------------------- DROP TABLE IF EXISTS `bms_post`; CREATE TABLE `bms_post` ( `id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键', `title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '标题', `content` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT 'markdown 内容', `user_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '作者 ID', `comments` int NOT NULL DEFAULT 0 COMMENT '评论统计', `collects` int NOT NULL DEFAULT 0 COMMENT '收藏统计', `view` int NOT NULL DEFAULT 0 COMMENT '浏览统计', `top` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否置顶,1-是,0-否', `essence` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否加精,1-是,0-否', `section_id` int NULL DEFAULT 0 COMMENT '专栏 ID', `create_time` datetime NOT NULL COMMENT '发布时间', `modify_time` datetime NULL DEFAULT NULL COMMENT '修改时间', UNIQUE INDEX `title`(`title`) USING BTREE, INDEX `user_id`(`user_id`) USING BTREE, INDEX `create_time`(`create_time`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '话题表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for bms_comment -- ---------------------------- DROP TABLE IF EXISTS `bms_comment`; CREATE TABLE `bms_comment` ( `id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键', `content` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '内容', `user_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '作者 ID', `topic_id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'topic_id', `create_time` datetime NOT NULL COMMENT '发布时间', `modify_time` datetime NULL DEFAULT NULL COMMENT '修改时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '评论表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Table structure for ums_user -- ---------------------------- DROP TABLE IF EXISTS `ums_user`; CREATE TABLE `ums_user` ( `id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户 ID', `username` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户名', `alias` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户昵称', `password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '密码', `avatar` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像', `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱', `mobile` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机', `score` int NOT NULL DEFAULT 0 COMMENT '积分', `token` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT 'token', `bio` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '个人简介', `active` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否激活,1:是,0:否', `status` bit(1) NULL DEFAULT b'1' COMMENT '状态,1:使用,0:停用', `role_id` int NULL DEFAULT NULL COMMENT '用户角色', `create_time` datetime NOT NULL COMMENT '加入时间', `modify_time` datetime NULL DEFAULT NULL COMMENT '修改时间', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `user_name`(`username`) USING BTREE, INDEX `user_email`(`email`) USING BTREE, INDEX `user_create_time`(`create_time`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of ums_user -- ---------------------------- INSERT INTO `ums_user` VALUES ('1349290158897311745', 'admin', 'admin', '$2a$10$8qx711TBg/2hxfL7N.sxf.0ROMhR/iuPhQx33IFqGd7PLgt5nGJTO', 'https://s3.ax1x.com/2020/12/01/DfHNo4.jpg', '[email protected]', NULL, 2, '', '自由职业者', b'1', b'1', NULL, '2021-01-13 17:40:17', NULL); INSERT INTO `ums_user` VALUES ('1349618748226658305', 'zhangsan', 'zhangsan', '$2a$10$7K3yYv8sMV5Xsc2facXTcuyDo8JQ4FJHvjZ7qtWYcJdei3Q6Fvqdm', 'https://s3.ax1x.com/2020/12/01/DfHNo4.jpg', '[email protected]', NULL, 0, '', '自由职业者', b'1', b'1', NULL, '2021-01-14 15:25:59', NULL); SET FOREIGN_KEY_CHECKS = 1; 

    创建 maven 工程

    1.pom 依赖

    <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.8.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> 
    <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <mybatis-plus.version>3.4.2</mybatis-plus.version> <fastjson.version>1.2.75</fastjson.version> <hutool.version>5.5.7</hutool.version> <jwt.version>0.9.1</jwt.version> <emoji-java.version>5.1.1</emoji-java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--jjwt--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jwt.version}</version> </dependency> <!--emoji-java 表情包--> <dependency> <groupId>com.vdurmont</groupId> <artifactId>emoji-java</artifactId> <version>${emoji-java.version}</version> </dependency> <!-- lettuce pool 缓存连接池--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <!--HuTool--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>${hutool.version}</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> <!--fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency> <!--yaml--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <!--bean validator--> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> 

    2.yam 配置

    # 端口号 server: port: 8081 # 数据库 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root url: jdbc:mysql://127.0.0.1:3306/nodepad_mblog?useUnicode=true&characterEncoding=utf8&autoRecOnnect=true&serverTimezOne=GMT%2B8 type: com.zaxxer.hikari.HikariDataSource # sql 日志打印 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 

    3.启动类

    // 我们这里还没有配置数据库,exclude = {DataSourceAutoConfiguration.class 就是启动时不加载数据库 // @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) @Slf4j @SpringBootApplication public class BlogApplication { public static void main(String[] args) { ConfigurableApplicationContext cOntext= SpringApplication.run(BlogApplication.class, args); String port = context.getEnvironment().getProperty("server.port"); log.info("http://localhost:"+port); } } 

    启动项目测试有没有报错

    4.项目返回和错误处理

    image-20210211175503499

    4.1api 数据返回

    IErrorCode
    public interface IErrorCode { /** * 错误编码: -1 失败;200 成功 * * @return 错误编码 */ Integer getCode(); /** * 错误描述 * * @return 错误描述 */ String getMessage(); } 
    ApiErrorCode
    public enum ApiErrorCode implements IErrorCode { /** * 成功 */ SUCCESS(200, "操作成功"), /** * 失败 */ FAILED(-1, "操作失败"), /** * 未登录,Token 过期 */ UNAUTHORIZED(401, "暂未登录或 token 已经过期"), /** * 权限不足 */ FORBIDDEN(403, "权限不足"), /** * 参数校验错误 */ VALIDATE_FAILED(404, "参数检验失败"); private final Integer code; private final String message; ApiErrorCode(int code, String message) { this.code = code; this.message = message; } @Override public Integer getCode() { return code; } @Override public String getMessage() { return message; } @Override public String toString() { return "ApiErrorCode{" + "code=" + code + ", message='" +message + '\'' + '}'; } } 
    ApiResult
    import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.Optional; @Data @NoArgsConstructor public class ApiResult<T> implements Serializable { private static final long serialVersiOnUID= -4153430394359594346L; /** * 业务状态码 */ private long code; /** * 结果集 */ private T data; /** * 接口描述 */ private String message; /** * 全参 * * @param code 业务状态码 * @param message 描述 * @param data 结果集 */ public ApiResult(long code, String message, T data) { this.code = code; this.message = message; this.data = data; } public ApiResult(IErrorCode errorCode) { errorCode = Optional.ofNullable(errorCode).orElse(ApiErrorCode.FAILED); this.code = errorCode.getCode(); this.message = errorCode.getMessage(); } /** * 成功 * * @param data 结果集 * @return {code:200,message:操作成功,data:自定义} */ public static <T> ApiResult<T> success() { return new ApiResult<T>(ApiErrorCode.SUCCESS.getCode(), ApiErrorCode.SUCCESS.getMessage(), null); } /** * 成功 * * @param data 结果集 * @return {code:200,message:操作成功,data:自定义} */ public static <T> ApiResult<T> success(T data) { return new ApiResult<T>(ApiErrorCode.SUCCESS.getCode(), ApiErrorCode.SUCCESS.getMessage(), data); } /** * 成功 * * @param data 结果集 * @param message 自定义提示信息 * @return {code:200,message:自定义,data:自定义} */ public static <T> ApiResult<T> success(T data, String message) { return new ApiResult<T>(ApiErrorCode.SUCCESS.getCode(), message, data); } /** * 失败返回结果 */ public static <T> ApiResult<T> failed() { return failed(ApiErrorCode.FAILED); } /** * 失败返回结果 * * @param message 提示信息 * @return {code:枚举 ApiErrorCode 取,message:自定义,data:null} */ public static <T> ApiResult<T> failed(String message) { return new ApiResult<T>(ApiErrorCode.FAILED.getCode(), message, null); } /** * 失败 * * @param errorCode 错误码 * @return {code:封装接口取,message:封装接口取,data:null} */ public static <T> ApiResult<T> failed(IErrorCode errorCode) { return new ApiResult<T>(errorCode.getCode(), errorCode.getMessage(), null); } /** * 失败返回结果 * * @param errorCode 错误码 * @param message 错误信息 * @return {code:枚举 ApiErrorCode 取,message:自定义,data:null} */ public static <T> ApiResult<T> failed(IErrorCode errorCode, String message) { return new ApiResult<T>(errorCode.getCode(), message, null); } /** * 参数验证失败返回结果 */ public static <T> ApiResult<T> validateFailed() { return failed(ApiErrorCode.VALIDATE_FAILED); } /** * 参数验证失败返回结果 * * @param message 提示信息 */ public static <T> ApiResult<T> validateFailed(String message) { return new ApiResult<T>(ApiErrorCode.VALIDATE_FAILED.getCode(), message, null); } /** * 未登录返回结果 */ public static <T> ApiResult<T> unauthorized(T data) { return new ApiResult<T>(ApiErrorCode.UNAUTHORIZED.getCode(), ApiErrorCode.UNAUTHORIZED.getMessage(), data); } /** * 未授权返回结果 */ public static <T> ApiResult<T> forbidden(T data) { return new ApiResult<T>(ApiErrorCode.FORBIDDEN.getCode(), ApiErrorCode.FORBIDDEN.getMessage(), data); } } 

    4.2 全局异常

    ApiException
    public class ApiException extends RuntimeException { private IErrorCode errorCode; public ApiException(IErrorCode errorCode) { super(errorCode.getMessage()); this.errorCode = errorCode; } public ApiException(String message) { super(message); } public IErrorCode getErrorCode() { return errorCode; } } 
    ApiAsserts
    public class ApiAsserts { /** * 抛失败异常 * * @param message 说明 */ public static void fail(String message) { throw new ApiException(message); } /** * 抛失败异常 * * @param errorCode 状态码 */ public static void fail(IErrorCode errorCode) { throw new ApiException(errorCode); } } 
    GlobalExceptionHandler
    import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Map; @ControllerAdvice public class GlobalExceptionHandler { /** * 捕获自定义异常 */ @ResponseBody @ExceptionHandler(value = ApiException.class) public ApiResult<Map<String, Object>> handle(ApiException e) { if (e.getErrorCode() != null) { return ApiResult.failed(e.getErrorCode()); } return ApiResult.failed(e.getMessage()); } } 

    1 条回复    2021-02-22 10:06:54 +08:00
    seven123
        1
    seven123  
       2021-02-22 10:06:54 +08:00
    不错,感谢
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2422 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 15:42 PVG 23:42 LAX 08:42 JFK 11:42
    Do have faith in wat you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86