前言:本文将介绍如何使用Vue和SpringBoot实现一个Markdown编辑器,其中Vue用于前端,SpringBoot用于后端,实现数据存储和接口调用。

项目背景

Markdown是一种轻量级的标记语言,用于简化文本编辑,最初由John Gruber于2004年创建,随着GitHub等开源平台的兴起,被广泛应用于编写技术博客、文档等场景之中。

Vue是一种流行的JavaScript框架,用于构建交互式的用户界面,在前端开发中被广泛应用。

SpringBoot是一种基于Java语言的开源框架,用于创建微服务、RESTful API等后端应用程序。

本项目将结合Vue和SpringBoot,实现一个Markdown编辑器,旨在探索Vue与SpringBoot在前后端开发中的应用。

技术栈

前端:

  • Vue
  • Vue Router
  • Vuex
  • axios
  • marked
  • highlight.js

后端:

  • SpringBoot 2.5.1
  • MyBatis
  • MySQL

功能列表

  • 用户注册/登录
  • Markdown编辑器
  • 支持文档上传、下载
  • 支持文档的增删改查

数据库设计

用户表

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(16) NOT NULL DEFAULT '',
  `password` varchar(32) NOT NULL DEFAULT '',
  `create_time` datetime NOT NULL,
  `update_time` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

文档表

CREATE TABLE `document` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `title` varchar(255) NOT NULL DEFAULT '',
  `content` text,
  `create_time` datetime NOT NULL,
  `update_time` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  CONSTRAINT `document_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

前端实现

前端代码结构如下:

.
├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   ├── api
│   ├── assets
│   ├── components
│   ├── router
│   ├── store
│   ├── utils
│   └── views
├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── babel.config.js
├── package-lock.json
└── package.json

路由设计

const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('@/views/Home.vue')
  },
  {
    path: '/login',
    name: 'Login',
    component: () => import('@/views/Login.vue')
  },
  {
    path: '/register',
    name: 'Register',
    component: () => import('@/views/Register.vue')
  },
  {
    path: '/editor',
    name: 'Editor',
    component: () => import('@/views/Editor.vue'),
    meta: {
      requireAuth: true
    }
  },
  {
    path: '/document/:id',
    name: 'Document',
    component: () => import('@/views/Document.vue'),
    meta: {
      requireAuth: true
    }
  },
  {
    path: '*',
    name: 'NotFound',
    component: () => import('@/views/NotFound.vue')
  }
]

状态管理

采用Vuex进行状态管理,主要存储用户登录信息和文档列表。

组件设计

Login(登录)

包括用户名和密码的输入框以及登录按钮。

Register(注册)

包括用户名、密码、确认密码的输入框和注册按钮。

Nav(导航栏)

包括LOGO、文档列表和个人信息按钮,可跳转到编辑器和个人中心页面。

Editor(编辑器)

包括文档标题和Markdown编辑器,可保存为草稿或发布为文章。

Document(文档详情)

展示文档的标题和内容,可进行编辑和删除。

NotFound(404页面)

展示页面不存在的提示信息。

封装API

使用axios封装了后台API,包括用户注册/登录、文档相关操作等。

import axios from 'axios'

const API_BASE_URL = 'http://localhost:8080/api'

export const register = (username, password) =>
  axios.post(`${API_BASE_URL}/register`, { username, password })

export const login = (username, password) =>
  axios.post(`${API_BASE_URL}/login`, { username, password })

export const logout = () => axios.post(`${API_BASE_URL}/logout`)

export const createDocument = (title, content) =>
  axios.post(`${API_BASE_URL}/documents`, { title, content })

export const updateDocument = (id, title, content) =>
  axios.put(`${API_BASE_URL}/documents/${id}`, { title, content })

export const deleteDocument = (id) => axios.delete(`${API_BASE_URL}/documents/${id}`)

export const getDocument = (id) => axios.get(`${API_BASE_URL}/documents/${id}`)

export const getDocuments = () => axios.get(`${API_BASE_URL}/documents`)

Markdown解析

使用marked.js和highlight.js解析Markdown文本和代码块,提高用户的阅读体验。

import marked from 'marked'
import hljs from 'highlight.js/lib/core'

marked.setOptions({
  highlight: (code, lang) => {
    if (lang && hljs.getLanguage(lang)) {
      return hljs.highlight(lang, code).value
    }
    return hljs.highlightAuto(code).value
  }
})

后端实现

后端代码结构如下:

.
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── demo
│   │   │               ├── controller
│   │   │               ├── dto
│   │   │               ├── interceptor
│   │   │               ├── mapper
│   │   │               ├── model
│   │   │               ├── security
│   │   │               ├── service
│   │   │               ├── util
│   │   │               └── DemoApplication.java
│   │   └── resources
│   │       ├── application-dev.yml
│   │       ├── application-prod.yml
│   │       ├── application.yml
│   │       ├── mapper
│   │       ├── static
│   │       ├── templates
│   │       └── logback-spring.xml
│   ├── test
│   │   └── java
│   │       └── com
│   │           └── example
│   │               └── demo
│   │                   └── DemoApplicationTests.java
│   ├── .gitignore
│   ├── mvnw
│   ├── mvnw.cmd
│   ├── pom.xml
│   └── README.md

数据库连接配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=UTC
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/**/*.xml
  type-aliases-package: com.example.demo.model

安全配置

通过Spring Security进行登录验证。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/register", "/api/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin().loginPage("/api/login").permitAll()
                .and()
                .logout().permitAll().logoutUrl("/api/logout").logoutSuccessUrl("/api/login");
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

数据库映射

使用MyBatis进行数据库映射。

@Mapper
public interface UserMapper {

    @Insert("INSERT INTO user(username, password, create_time, update_time) " +
            "VALUES(#{username}, #{password}, #{createTime}, #{updateTime})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(User user);

    @Select("SELECT * FROM user WHERE username = #{username}")
    User findByUsername(String username);
}

@Mapper
public interface DocumentMapper {

    @Insert("INSERT INTO document(user_id, title, content, create_time, update_time) " +
            "VALUES(#{userId}, #{title}, #{content}, #{createTime}, #{updateTime})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(Document document);

    @Update("UPDATE document SET title = #{title}, content = #{content}, update_time = #{updateTime} WHERE id = #{id}")
    int update(Document document);

    @Delete("DELETE FROM document WHERE id = #{id}")
    int delete(int id);

    @Select("SELECT * FROM document WHERE id = #{id}")
    Document findById(int id);

    @Select("SELECT * FROM document WHERE user_id = #{userId}")
    List<Document> findByUserId(int userId);
}

RESTful API

后端提供了以下API接口:

  • /register(POST):注册新用户
  • /login(POST):用户登录
  • /logout(POST):用户退出登录
  • /documents(POST):创建新文档
  • /documents/:id(PUT):更新文档
  • /documents/:id(DELETE):删除文档
  • /documents/:id(GET):获取指定ID文档
  • /documents(GET):获取所有文档

总结

本文介绍了如何使用Vue和SpringBoot实现一个Markdown编辑器,涉及了前后端开发中的状态管理、路由设计、API封装、Markdown解析和数据库映射等方面内容。通过本项目,读者可以掌握Vue和SpringBoot在前后端开发中的应用及其基本原理。

Logo

前往低代码交流专区

更多推荐