111.【金橘社区1.0】

news2024/11/24 0:21:29

金橘社区1.0版本

  • (一)、SpringBoot整合SpringSecurity
    • 1.导入依赖
    • 2.数据库
    • 3.登入表单
    • 4. 添加配置类 SecurityConfig
    • 5.接口实现类 CkqnUserServiceImpl
    • 6.前端认证问题
  • (二)、SpringBoot整合Ajax
    • 1.登入表单
    • 2. JavaScript
  • (三)、SpringBoot整合editor.md
    • 1.编写页面
        • (1).前端页面
        • (2).后端页面
    • 2.修改文件
        • (1).前端页面
        • (2).后端页面
    • 3.文章展示
        • (1).前端页面
        • (2).后端页面
    • 4.Aax 密码验证
  • (三)、知识点新发现
    • 1. template包中创建包静态资源路径一样.
    • 2. SpringBoot自定义400、500错误。只需要在template包下创建error包即可。
    • 3. 加入我们要使用mybatis-plus那么条件构造其实际上就是对SQL的拼接操作。构造器的泛型是: 实体类
    • 4.我们在验证登入操作的时候,只需要根据username进行判断即可,因为这样可以减少对数据库的一次访问
  • (四)、金橘社区前端设计
    • 1. 渐变动态背景CSS .
    • 2. sleep() 休眠的工具类
    • 3. 利用JS页面的跳转,我们一定要用异步跳转
    • 4. 好看的动态背景推荐
    • 6. 炫酷的搜索框
    • 7. 返回顶部
    • 8. 特效烟花点击
    • 9. 前端引入 markdown编辑器 ---- 一定要和html处于同级目录下.
    • 10. 百度搜索框
    • 11. 二维码弹窗!!!!!
    • 12. 文本框不能为空格的属性,一个属性就可以

(一)、SpringBoot整合SpringSecurity

金橘社区官网: http://www.jsxs1.cn/

1.导入依赖

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.jsxs</groupId>
    <artifactId>Kumquat</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Kumquat</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!--web 依赖   -->
        <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>
        <!--     JDBC驱动器   -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--mysql连接驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
        <!--自动生成代码依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.5.22</version>
        </dependency>
        <!--     thymeleaf   -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
            <version>2.7.7</version>
        </dependency>
        <!--   lombok     -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--    JSON-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.26</version>
        </dependency>
        <!--SpringSecurity -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
            <version>3.0.4.RELEASE</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <skip>true</skip>
            </configuration>
        </plugin>
        </plugins>
    </build>
</project>

2.数据库

CREATE DATABASE CQAN;
USE CQAN;

# 用户表

CREATE TABLE `ckqn_user` (
  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '自增id',
  `uid` varchar(200) NOT NULL COMMENT '用户编号',
  `role_id` int(10) NOT NULL COMMENT '角色编号',
  `username` varchar(100) NOT NULL COMMENT '用户名',
  `password` varchar(200) NOT NULL COMMENT '密码',
  `avatar` varchar(500) NOT NULL DEFAULT '/images/avatar/avatar-1.jpg' COMMENT '头像',
  `login_date` datetime NOT NULL COMMENT '登录时间',
  `gmt_create` datetime NOT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=840 DEFAULT CHARSET=utf8;
# 用户角色

CREATE TABLE `ckqn_user_role` (
  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '角色编号',
  `name` varchar(200) NOT NULL COMMENT '角色名称',
  `description` varchar(500) NOT NULL DEFAULT '无描述...' COMMENT '角色描述',
  `gmt_create` datetime NOT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

3.登入表单

       <form th:action="@{/code}" method="post">
          <div class="inputBox">
            <input type="text" placeholder="账户ID" name="username" id="name" required onblur="a1()" onkeyup="this.value=this.value.replace(/\s+/g,'')">
            <i id="username" style="z-index: 9999"></i>

          </div>
          <div class="inputBox">
            <input type="password" placeholder="密码" name="password" required onkeyup="this.value=this.value.replace(/\s+/g,'')">

          </div>
          <div class="inputBox">
            <input type="submit" value="登录">
          </div>
          <p class="forget">忘记密码?<a href="#">
            点击这里
          </a></p>
          <p class="forget">没有账户?<a href="#">
            注册
          </a></p>
        </form>

4. 添加配置类 SecurityConfig

package com.jsxs.kumquat.config;

import com.jsxs.kumquat.service.impl.CkqnUserServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @Author Jsxs
 * @Date 2023/4/10 20:56
 * @PackageName:com.jsxs.kumquat.config
 * @ClassName: SecurityConfig
 * @Description: TODO  授权文件
 * @Version 1.0
 */
@EnableWebSecurity
@Configuration
@Component
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //  调用的是业务实现类
    @Resource
    private CkqnUserServiceImpl ckqnUserService;

    // 密码加密方式
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 认证
     *
     * @param http
     * @throws Exception permitAll -> 无条件访问
     *                   authenticated -> 需要认证才能访问, /* 除了无条件的,其他都加上锁
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //  首页所有人可以访问,但是功能页只有对应有权限的人才能访问
        http.authorizeRequests()
                .antMatchers("/", "/index.html", "/login.html", "/mainMenu.html", "/JsxsRoad.html", "/recommendedArticles.html", "/code", "/a3").permitAll()
                .antMatchers("/*").authenticated();
        super.configure(http);
        http.formLogin().loginPage("/login.html");

        // 登录配置
        http.formLogin()
                .usernameParameter("username") // 这个参数必须为username (约定大于配置)
                .passwordParameter("password") // 这个参数必须为password (约定大于配置)
                .loginPage("/login.html")  //登入页面是哪个?
                .loginProcessingUrl("/code") // 点击提交的时候跳转到哪里?
                .defaultSuccessUrl("/"); // 密码验证通过后我们跳转到哪里?
       
        // 注销配置
        http.headers().contentTypeOptions().disable();
        http.headers().frameOptions().disable(); // 图片跨域
        http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求(ajax如果要使用一定开启)
        http.logout().logoutSuccessUrl("/");
    }

    /**
     * 
     * @param auth
     * @throws Exception userDetailsService-》对哪个业务进行操作,passwordEncoder-》密码加密方式
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(ckqnUserService).passwordEncoder(passwordEncoder());
    }

    /**
     * 
     * @param web
     * @throws Exception 对静态资源不拦截: static目录可以省略
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/css/**", "/assets/**", "/plugins/**", "/img/**", "/editor.md/**", "/Jquery/**", "/layui/**", "/qrcode/**");
    }

}

5.接口实现类 CkqnUserServiceImpl

CkqnUserServiceImpl

package com.jsxs.kumquat.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jsxs.kumquat.pojo.CkqnUser;
import com.jsxs.kumquat.mapper.CkqnUserMapper;
import com.jsxs.kumquat.pojo.CkqnUserRole;
import com.jsxs.kumquat.service.CkqnUserRoleService;
import com.jsxs.kumquat.service.CkqnUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 吉士先生
 * @since 2023-04-09
 * TODO 这里需要继承一个接口: UserDetailsService
 */
@Service
public class CkqnUserServiceImpl extends ServiceImpl<CkqnUserMapper, CkqnUser> implements CkqnUserService, UserDetailsService {
    // 1. 业务层接口
    @Resource
    CkqnUserService userService;
    // 2. 认证角色层接口
    @Resource
    CkqnUserRoleService roleService;
    // 3.session
    @Resource
    HttpSession session;

    /**
     * TODO 用户逻辑和认证
     *
     * @param uid
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String uid) throws UsernameNotFoundException {
        // 4. 通过用户名查询用户
        CkqnUser user = userService.getOne(new QueryWrapper<CkqnUser>().eq("uid", uid));

        // 5. 查询到的角色放入session
        session.setAttribute("loginUser", user);

        // 7.创建一个新的UserDetails对象,最后验证登陆的需要
        UserDetails userDetails = null;
        if (user != null) {
            System.out.println("未加密:" + user.getPassword());
            // 8.加密密码
            String BCryptPassword = new BCryptPasswordEncoder().encode(user.getPassword());
            // 登录后会将登录密码进行加密,然后比对数据库中的密码,数据库密码需要加密存储!
//            String password = user.getPassword();

            // 9. 创建一个集合来存放权限
            Collection<GrantedAuthority> authorities = getAuthorities(user);
            /**
             * TODO 实例化UserDetails对象
             * uid-> 前端username框传过来的数据
             * BCryptPassword-> 加密后的密码
             * authorities -》 认证列表
             */
            userDetails = new org.springframework.security.core.userdetails.User(uid, BCryptPassword,
                    true,
                    true,
                    true,
                    true, authorities);
        }
        return userDetails;
    }

    /**
     * @param user ->实体类
     * @return
     */
    private Collection<GrantedAuthority> getAuthorities(CkqnUser user) {
        List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>();
        // 1. 通过用户的第三个字段roleID再另一个表中查找数据据
        CkqnUserRole role = roleService.getById(user.getRoleId());
        // 2. 注意:这里每个权限前面都要加ROLE_。否在最后验证不会通过
        authList.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
        return authList;
    }
}

两张表
在这里插入图片描述

6.前端认证问题

xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
sec:authorize="!isAuthenticated()" 没有被认证就是显示
sec:authorize="isAuthenticated()" 认证了才被显示

(二)、SpringBoot整合Ajax

1.登入表单

       <form th:action="@{/code}" method="post">
          <div class="inputBox">
            <input type="text" placeholder="账户ID" name="username" id="name" required onblur="a1()" onkeyup="this.value=this.value.replace(/\s+/g,'')">
            <--*******id 为username, 上面id为name-->
            <i id="username" style="z-index: 9999"></i>

          </div>
          <div class="inputBox">
            <input type="password" placeholder="密码" name="password" required onkeyup="this.value=this.value.replace(/\s+/g,'')">

          </div>
          <div class="inputBox">
            <input type="submit" value="登录">
          </div>
          <p class="forget">忘记密码?<a href="#">
            点击这里
          </a></p>
          <p class="forget">没有账户?<a href="#">
            注册
          </a></p>
        </form>

2. JavaScript

 // AJAX  -js
<script src="Jquery/jquery-3.6.1.js"></script> 
  function a1(){
    $.post({
      url:"http://localhost:8080/a3",
      data:{'name':$("#name").val()},
      success:function(data){
        if(data.toString()=='OK'){
          $("#username").css("color","green");
        }else{
          $("#username").css("color","red");
        }
        $("#username").html(data);
      }
    });
  }
  function a2(){
    $.post({
      url: "http://localhost:8080/a3",
      data: {'pwd': $("#pwd").val()},
      success: function (data) {
        if (data.toString()=='OK') {
          $("#userpwd").css("color", "green");
        } else {
          $("#userpwd").css("color", "red");
        }
        $("#userpwd").html(data);
      }
    });
  }

(三)、SpringBoot整合editor.md

前提需要我们导入editor.md的插件文件
在这里插入图片描述

1.编写页面

(1).前端页面

引入文件

 	<link rel="stylesheet" href="{/editor.md/examples/css/style.css" th:href="@{/editor.md/examples/css/style.css/}">
    <link rel="stylesheet" href="/editor.md/css/editormd.css" th:href="@{/editor.md/css/editormd.css}"/>
    <link rel="shortcut icon" href="https://pandao.github.io/editor.md/favicon.ico" type="image/x-icon"/>
    <script src="Jquery/jquery-3.6.1.js"></script>

在这里编写文件

        <div id="test-editormd">
            <textarea style="display:none;" name="content"></textarea>
        </div>

配置JS

<script src="/editor.md/examplesjs/jquery.min.js" th:src="@{/editor.md/examples/js/jquery.min.js}"></script>
<script src="/editor.md/editormd.js" th:src="@{/editor.md/editormd.js}"></script>
<script type="text/javascript">
    var testEditor;

    $(function () {

        $.get('/editor.md/examples/test.md', function (md) {
        //  这里的第一个参数,指的是:"编写页面的id": 第二个参数是: "配置" 
            testEditor = editormd("test-editormd", {
                width: "100%",  // 1.宽度
                height: "750px", // 2.高度
                path: '/editor.md/lib/', //3.配置文件 
                theme: "dark", //4.主题
                markdown:'#欢迎您来到金橘社区!!', //5.默认编辑页面
                // previewTheme: "dark",
                editorTheme: "pastel-on-dark", // 6.编辑页面主题
                imageUpload: true,   //7.文件上传
                imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp"],  
                imageUploadURL: "/article/image/upload",  //8.图片上传URL
                toolbarIcons: function () { //9.组件
                    return ["undo", "redo", "|", "bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase", "|", "h1", "h2", "h3", "h4", "h5", "h6", "|", "list-ul", "list-ol", "hr", "|", "link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime", "emoji", "html-entities", "pagebreak", "|", "goto-line", "watch", "preview", "fullscreen", "clear", "search", "|", "help", "info", "||", "publish"];
                },

                toolbarIconTexts: { //10.自定义发布按钮的组件
                    publish: "<span bgcolor='gray' style='font-family: 微软雅黑;font-weight: bold;color: #00FF00'>发布</span>"
                },

                toolbarHandlers: { //11. 提交文章上传的路径
                    publish: function (cm, icon, cursor, selection) {
                        mdEditorForm.method = "post";
                        mdEditorForm.action = "/article/publish";//提交至服务器的路径
                        mdEditorForm.submit();
                    }
                }
            });
        });
    });
</script>

全部文档信息

<!DOCTYPE html>
<html lang="zh" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
    <meta charset="utf-8"/>
    <title>金橘社区-文章编写</title>
    <link rel="stylesheet" href="{/editor.md/examples/css/style.css" th:href="@{/editor.md/examples/css/style.css/}">
    <link rel="stylesheet" href="/editor.md/css/editormd.css" th:href="@{/editor.md/css/editormd.css}"/>
    <link rel="shortcut icon" href="https://pandao.github.io/editor.md/favicon.ico" type="image/x-icon"/>
    <link rel="stylesheet" href="layui/css/layui.css" media="all">
    <script src="layui/layui.js" charset="utf-8"></script>
    <script src="Jquery/jquery-3.6.1.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .top-search {
            width: 680px;
            height: 45px;
            margin: 30px auto;

        }

        .search-box {
            display: flex;
            position: relative;
        }

        .search-left {
            width: 545px;
            height: 45px;
            border: 2px solid rgb(196, 199, 206);
            border-top-left-radius: 10px;
            border-bottom-left-radius: 10px;
            outline-color: rgb(242, 78, 130);
        }

        .icon-xiangji {
            position: absolute;
            right: 150px;
            top: 12px;
            font-size: 24px;
            color: rgb(196, 199, 206);
        }

        .search-right {
            color: #fff;
            font-size: 18px;
            width: 110px;
            height: 49px;
            border: 0px;
            border-top-right-radius: 10px;
            border-bottom-right-radius: 10px;
            background-color: rgb(242, 78, 130);
        }

        #su:hover {
            background: #14dc99;
        }
    </style>
</head>
<body>
<form name="mdEditorForm" method="post">
<div class="top-search" style="margin-top: 13px;">
    <button type="button" class="layui-btn layui-btn-primary1 layui-btn-lg" style="margin-top: 7px;margin-left: -1200px;"
            onclick="document.location.href='MyArticals.html'"><i class="layui-icon layui-icon-return"
                                                                  style="font-size: 20px; color: #1E9FFF;"></i><i
            style="color: #0e0c0d;font-family: 微软雅黑;font-weight: bold" onclick="return confirm('您还未保存,如果直接退出将不会保存数据。您确定直接退出?')">文章管理</i></button>
    <div class="search-box" style="    top: -45px;">
        <input type="text" name="title" class="search-left" placeholder="     请 输 入 文 章 标 题" required
               style="font-size: 20px;font-family: 微软雅黑;font-weight: bold;"
               onkeyup="this.value=this.value.replace(/\s+/g,'')"
        value="【无标题】">
        <span class="iconfont icon-xiangji"></span>
    </div>
    <ul sec:authorize="!isAuthenticated()" class="layui-nav" lay-bar="disabled" style="width: 40px; height: 0px;margin-left: 863px;margin-top: -100px;z-index: 9999">
        <li  class="layui-nav-item" lay-unselect="">
            <a href="javascript:;"><img src="/img/login.png" tppabs="http://t.cn/RCzsdCq" class="layui-nav-img" onclick="document.location.href='login.html'"></a>
            <dl class="layui-nav-child">
                <dd><a href="javascript:;" onclick="document.location.href='login.html'">登入</a></dd>
            </dl>
        </li>
    </ul>
    <ul sec:authorize="hasRole('ROLE_A')" class="layui-nav" lay-bar="disabled" style="width: 40px; height: 0px;margin-left: 863px;margin-top: -100px;z-index: 9999">
        <li  class="layui-nav-item" lay-unselect="">
            <a href="javascript:;"><img src="/img/user.jpg" tppabs="http://t.cn/RCzsdCq" class="layui-nav-img" onclick="document.location.href='#'"></a>
            <dl class="layui-nav-child">
                <dd><a href="javascript:;">个人中心</a></dd>
                <dd><a href="javascript:;" th:href="@{/login.html}">切换账号</a></dd>
                <dd><a href="javascript:;" th:href="@{/logout}">注销</a></dd>
            </dl>
        </li>
    </ul>
    <ul class="layui-nav" lay-bar="disabled" style="width: 40px; height: 0px;margin-left: 863px;margin-top: -100px;z-index: 9999">
        <li sec:authorize="hasRole('ROLE_B')" class="layui-nav-item" lay-unselect="">
            <a href="javascript:;"><img src="/img/user2.jpg" tppabs="http://t.cn/RCzsdCq" class="layui-nav-img" onclick="document.location.href='#'"></a>
            <dl class="layui-nav-child">
                <dd><a href="javascript:;">个人中心</a></dd>
                <dd><a href="javascript:;" onclick="document.location.href='login.html'">切换账号</a></dd>
                <dd><a href="javascript:;" th:href="@{/logout}">注销</a></dd>
            </dl>
        </li>
    </ul>
</div>
<div id="layout" style="margin-top: -41px;">
    <header>
    </header>
        <div id="test-editormd">
            <textarea style="display:none;" name="content"></textarea>
        </div>

</div>
</form>
<script src="/editor.md/examplesjs/jquery.min.js" th:src="@{/editor.md/examples/js/jquery.min.js}"></script>
<script src="/editor.md/editormd.js" th:src="@{/editor.md/editormd.js}"></script>
<script type="text/javascript">
    var testEditor;

    $(function () {

        $.get('/editor.md/examples/test.md', function (md) {
            testEditor = editormd("test-editormd", {
                width: "100%",
                height: "750px",
                path: '/editor.md/lib/',
                theme: "dark",
                markdown:'#欢迎您来到金橘社区!!',
                // previewTheme: "dark",
                editorTheme: "pastel-on-dark",
                imageUpload: true,
                imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
                imageUploadURL: "/article/image/upload",
                toolbarIcons: function () {
                    return ["undo", "redo", "|", "bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase", "|", "h1", "h2", "h3", "h4", "h5", "h6", "|", "list-ul", "list-ol", "hr", "|", "link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime", "emoji", "html-entities", "pagebreak", "|", "goto-line", "watch", "preview", "fullscreen", "clear", "search", "|", "help", "info", "||", "publish"];
                },

                toolbarIconTexts: {
                    publish: "<span bgcolor='gray' style='font-family: 微软雅黑;font-weight: bold;color: #00FF00'>发布</span>"
                },

                toolbarHandlers: {
                    publish: function (cm, icon, cursor, selection) {
                        mdEditorForm.method = "post";
                        mdEditorForm.action = "/article/publish";//提交至服务器的路径
                        mdEditorForm.submit();
                    }
                }
            });
        });
    });
</script>
</body>
</html>

(2).后端页面

工具类

package com.jsxs.kumquat.utils;

/**
 * @Author Jsxs
 * @Date 2023/4/11 15:50
 * @PackageName:com.jsxs.kumquat.utils
 * @ClassName: FileUtils
 * @Description: TODO
 * @Version 1.0
 */

import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

/**
 * 文件上传工具类
 */
public class FileUtils {

    private static final String prePath = System.getProperty("user.dir") + "/src/main/resources/static/upload/";

    /**
     * 上传文件
     * @param file
     * @return 返回文件路径(以相对路径放回)
     */
    public static String uploadFile(MultipartFile file) {
        if(file.isEmpty()) {
            return "";
        }
        // 获取原文件名
        String originFileName = file.getOriginalFilename();
        // 我们通过UUID 来重新重组文件名
        String uid = UUID.randomUUID().toString();
        assert originFileName != null;
        String suffix = originFileName.substring(originFileName.lastIndexOf('.') + 1);
        String path = prePath + uid + "." + suffix;

        String returnPath = "/upload/" + uid + "." + suffix;
        File newFile = new File(path);
        if(newFile.getParentFile() != null && !newFile.getParentFile().exists()) {
            System.out.println("创建目录ing");
            // 上面的 newFile.getParentFile() 已经保证了不为null.
            if(newFile.getParentFile().mkdirs()) {
                System.out.println("创建目录成功");
            }else {
                System.out.println("创建目录失败");
                return "";
            }
        }
        try {
            file.transferTo(newFile);
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
        return returnPath;
    }

}

文件上传

package com.jsxs.kumquat.controller;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jsxs.kumquat.pojo.CkqnBlog;
import com.jsxs.kumquat.pojo.CkqnUser;
import com.jsxs.kumquat.service.CkqnBlogService;
import com.jsxs.kumquat.utils.FileUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.UUID;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author 吉士先生
 * @since 2023-04-09
 */
@Controller
@RequestMapping("/article")
public class CkqnBlogController {
    @Resource
    CkqnBlogService ckqnBlogService;
    @Resource
    HttpSession session;
    // 文章上传
    @RequestMapping("/publish")
    public String publishArticle(CkqnBlog article) {
        CkqnUser user = (CkqnUser) session.getAttribute("loginUser");
        // 1.作者信息
        article.setAuthorId(user.getUid());
        article.setAuthorName(user.getUsername());
        article.setAuthorAvatar(user.getAvatar());
        // 2.博客ID
        String replace = UUID.randomUUID().toString().replace("-", "");
        article.setBid(replace);
        if (article.getTitle() == null) {
            System.out.println("标题为空?????????");
        }
        boolean res = ckqnBlogService.save(article);
        if (res) {
            return "tipSuccess";
        }
        return "tipFalse";
    }
    // 图片上传
    @RequestMapping("/image/upload")
    @ResponseBody
    public JSONObject imageUpload(@RequestParam("editormd-image-file") MultipartFile image) {
        JSONObject jsonObject = new JSONObject();
        if (image != null) {
            String path = FileUtils.uploadFile(image);
//            回调给 editor
            System.out.println(path);
            jsonObject.put("url", path);
            jsonObject.put("success", 1);
            jsonObject.put("message", "upload success!");
            return jsonObject;
        }
        jsonObject.put("success", 0);
        jsonObject.put("message", "upload error!");
        return jsonObject;
    }

    //  1.一篇详细文章
    @RequestMapping("/get/{id}")
    public ModelAndView getArticleById(@PathVariable(name = "id") int id) {
        ModelAndView modelAndView = new ModelAndView();
        CkqnBlog article = ckqnBlogService.getById(id);

        modelAndView.setViewName("WriteCenter/article");
        if (article == null) {
            modelAndView.addObject("article", new CkqnBlog());
        }
        modelAndView.addObject("article", article);
        return modelAndView;
    }

2.修改文件

(1).前端页面

需要引入数据

	<link rel="stylesheet"  th:href="@{/editor.md/examples/css/style.css/}">
  <link rel="stylesheet"  th:href="@{/editor.md/css/editormd.css}"/>
  <link rel="shortcut icon" href="https://pandao.github.io/editor.md/favicon.ico" type="image/x-icon"/>
  <script th:src="@{/Jquery/jquery-3.6.1.js}"></script>

被修改页面的展示

    <div class="col-md-12 mb-3">
      <div id="blog-content">
        <textarea required name="content" th:text="${blog.getContent()}" id="content" style="display:none;" rows="3" class="form-control"> </textarea>
      </div>
    </div>

js

<script th:src="@{/editor.md/examples/js/jquery.min.js}"></script>
<script th:src="@{/editor.md/editormd.js}"></script>
<script type="text/javascript">
  var testEditor;
  $(function() {
    testEditor = editormd("blog-content", {
      width : "100%", //1.
      height : "750px", //2.
      syncScrolling : "single", //3.单页
        path: '/editor.md/lib/', //4.路径
        theme: "dark", //5.黑暗主题
        previewTheme: "gary",
        editorTheme: "pastel-on-dark",
        imageUpload: true, //6.文件上传
        imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
        imageUploadURL: "/article/image/upload",  //7.文件上传对象
      onload : function() {
        console.log('onload', this);
      },
        toolbarIcons: function () {
          return ["undo", "redo", "|", "bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase", "|", "h1", "h2", "h3", "h4", "h5", "h6", "|", "list-ul", "list-ol", "hr", "|", "link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime", "emoji", "html-entities", "pagebreak", "|", "goto-line", "watch", "preview", "fullscreen", "clear", "search", "|", "help", "info", "||", "publish"];
        },

        toolbarIconTexts: {  //8. 提交修改的按钮
          publish: "<span bgcolor='gray' style='color: #00FF00;font-weight: bold;font-family: 微软雅黑'>提交修改</span>"
        },

        toolbarHandlers: { //9.修改文章的路径
          publish: function (cm, icon, cursor, selection) {
            mdEditorForm.method = "post";
            mdEditorForm.action = "/article/toupdate";//提交至服务器的路径
            mdEditorForm.submit();
          }
        },
      onfullscreen : function() {
        console.log("onfullscreen");
        document.getElementsByClassName("navbar")[0].style.display="none";
      },
      onfullscreenExit : function() {
        console.log("onfullscreenExit");
        document.getElementsByClassName("navbar")[0].style.display="";
      }
      });
    });
</script>

全部前端

<!DOCTYPE html>
<html lang="zh" xmlns:sec="http://www.thymeleaf.org/extras/spring-security" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="utf-8"/>
  <title>金橘社区-文章修改</title>
  <link rel="stylesheet"  th:href="@{/editor.md/examples/css/style.css/}">
  <link rel="stylesheet"  th:href="@{/editor.md/css/editormd.css}"/>
  <link rel="shortcut icon" href="https://pandao.github.io/editor.md/favicon.ico" type="image/x-icon"/>
  <link rel="stylesheet" th:href="@{/layui/css/layui.css}" media="all">
  <script th:src="@{/layui/layui.js}" charset="utf-8"></script>
  <script th:src="@{/Jquery/jquery-3.6.1.js}"></script>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .top-search {
      width: 680px;
      height: 45px;
      margin: 30px auto;

    }

    .search-box {
      display: flex;
      position: relative;
    }

    .search-left {
      width: 545px;
      height: 45px;
      border: 2px solid rgb(196, 199, 206);
      border-top-left-radius: 10px;
      border-bottom-left-radius: 10px;
      outline-color: rgb(242, 78, 130);
    }

    .icon-xiangji {
      position: absolute;
      right: 150px;
      top: 12px;
      font-size: 24px;
      color: rgb(196, 199, 206);
    }

    .search-right {
      color: #fff;
      font-size: 18px;
      width: 110px;
      height: 49px;
      border: 0px;
      border-top-right-radius: 10px;
      border-bottom-right-radius: 10px;
      background-color: rgb(242, 78, 130);
    }

    #su:hover {
      background: #14dc99;
    }

  </style>
</head>
<body>
<form name="mdEditorForm" method="post">
  <!-- 隐藏域 uid -->
  <input type="hidden" name="bid" th:value="${blog.getBid()}">
  <div class="top-search" style="margin-top: 13px;">
    <a type="button" class="layui-btn layui-btn-primary1 layui-btn-lg" style="margin-top: 7px;margin-left: -1200px;"
            th:href="@{/MyArticals.html}"><i class="layui-icon layui-icon-return"
                                             style="font-size: 20px; color: #1E9FFF;"></i><i
            style="color: #0e0c0d;font-family: 微软雅黑;font-weight: bold" onclick="return confirm('您还未保存更改数据,如果直接退出将不会保存更改的数据。您确定直接退出?')">文章管理</i></a>
    <div class="search-box" style="    top: -45px;">
<!--      标题-->
      <input type="text" name="title" class="search-left" placeholder="     请 输 入 文 章 标 题" required
             style="font-size: 20px;font-family: 微软雅黑;font-weight: bold;"
             onkeyup="this.value=this.value.replace(/\s+/g,'')"
             th:value="${blog.title}">
      <span class="iconfont icon-xiangji"></span>
    </div>
    <ul class="layui-nav" lay-bar="disabled" style="width: 40px; height: 0px;margin-left: 863px;margin-top: -100px;z-index: 9999">
      <li sec:authorize="!isAuthenticated()" class="layui-nav-item" lay-unselect="">
        <a href="javascript:;"><img src="/img/login.png" tppabs="http://t.cn/RCzsdCq" class="layui-nav-img" onclick="document.location.href='login.html'"></a>
        <dl class="layui-nav-child">
          <dd><a href="javascript:;" onclick="document.location.href='login.html'">登入</a></dd>
        </dl>
      </li>
    </ul>
    <ul class="layui-nav" lay-bar="disabled" style="width: 40px; height: 0px;margin-left: 863px;margin-top: -100px;z-index: 9999">
      <li sec:authorize="isAuthenticated()" class="layui-nav-item" lay-unselect="">
        <a href="javascript:;"><img src="/img/user.jpg" tppabs="http://t.cn/RCzsdCq" class="layui-nav-img" onclick="document.location.href='#'"></a>
        <dl class="layui-nav-child">
          <dd><a href="javascript:;">个人中心</a></dd>
          <dd><a href="javascript:;" th:href="@{/login.html}">切换账号</a></dd>
          <dd><a href="javascript:;" th:href="@{/logout}">注销</a></dd>
        </dl>
      </li>
    </ul>
  </div>
  <div id="layout" style="margin-top: -41px;">
    <header>
    </header>
    <div class="col-md-12 mb-3">
      <div id="blog-content">
        <textarea required name="content" th:text="${blog.getContent()}" id="content" style="display:none;" rows="3" class="form-control"> </textarea>
      </div>
    </div>
  </div>
  </div>
</form>
<script th:src="@{/editor.md/examples/js/jquery.min.js}"></script>
<script th:src="@{/editor.md/editormd.js}"></script>
<script type="text/javascript">
  var testEditor;
  $(function() {
    testEditor = editormd("blog-content", {
      width : "100%",
      height : "750px",
      syncScrolling : "single",
        path: '/editor.md/lib/',
        theme: "dark",
        previewTheme: "gary",
        editorTheme: "pastel-on-dark",
        imageUpload: true,
        imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
        imageUploadURL: "/article/image/upload",
      onload : function() {
        console.log('onload', this);
      },
        toolbarIcons: function () {
          return ["undo", "redo", "|", "bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase", "|", "h1", "h2", "h3", "h4", "h5", "h6", "|", "list-ul", "list-ol", "hr", "|", "link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime", "emoji", "html-entities", "pagebreak", "|", "goto-line", "watch", "preview", "fullscreen", "clear", "search", "|", "help", "info", "||", "publish"];
        },

        toolbarIconTexts: {
          publish: "<span bgcolor='gray' style='color: #00FF00;font-weight: bold;font-family: 微软雅黑'>提交修改</span>"
        },

        toolbarHandlers: {
          publish: function (cm, icon, cursor, selection) {
            mdEditorForm.method = "post";
            mdEditorForm.action = "/article/toupdate";//提交至服务器的路径
            mdEditorForm.submit();
          }
        },
      onfullscreen : function() {
        console.log("onfullscreen");
        document.getElementsByClassName("navbar")[0].style.display="none";
      },
      onfullscreenExit : function() {
        console.log("onfullscreenExit");
        document.getElementsByClassName("navbar")[0].style.display="";
      }
      });
    });
</script>
</body>
</html>

(2).后端页面

package com.jsxs.kumquat.controller;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jsxs.kumquat.pojo.CkqnBlog;
import com.jsxs.kumquat.pojo.CkqnUser;
import com.jsxs.kumquat.service.CkqnBlogService;
import com.jsxs.kumquat.utils.FileUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.UUID;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author 吉士先生
 * @since 2023-04-09
 */
@Controller
@RequestMapping("/article")
public class CkqnBlogController {
    @Resource
    CkqnBlogService ckqnBlogService;
    @Resource
    HttpSession session;
    // 文章上传
    @RequestMapping("/publish")
    public String publishArticle(CkqnBlog article) {
        CkqnUser user = (CkqnUser) session.getAttribute("loginUser");
        // 1.作者信息
        article.setAuthorId(user.getUid());
        article.setAuthorName(user.getUsername());
        article.setAuthorAvatar(user.getAvatar());
        // 2.博客ID
        String replace = UUID.randomUUID().toString().replace("-", "");
        article.setBid(replace);
        if (article.getTitle() == null) {
            System.out.println("标题为空?????????");
        }
        boolean res = ckqnBlogService.save(article);
        if (res) {
            return "tipSuccess";
        }
        return "tipFalse";
    }
    // 文件上传
    @RequestMapping("/image/upload")
    @ResponseBody
    public JSONObject imageUpload(@RequestParam("editormd-image-file") MultipartFile image) {
        JSONObject jsonObject = new JSONObject();
        if (image != null) {
            String path = FileUtils.uploadFile(image);
//            回调给 editor
            System.out.println(path);
            jsonObject.put("url", path);
            jsonObject.put("success", 1);
            jsonObject.put("message", "upload success!");
            return jsonObject;
        }
        jsonObject.put("success", 0);
        jsonObject.put("message", "upload error!");
        return jsonObject;
    }

    //  1.一篇详细文章
    @RequestMapping("/get/{id}")
    public ModelAndView getArticleById(@PathVariable(name = "id") int id) {
        ModelAndView modelAndView = new ModelAndView();
        CkqnBlog article = ckqnBlogService.getById(id);

        modelAndView.setViewName("WriteCenter/article");
        if (article == null) {
            modelAndView.addObject("article", new CkqnBlog());
        }
        modelAndView.addObject("article", article);
        return modelAndView;
    }

    // 开始修改
    @RequestMapping("/update/editor/{authorId}/{bid}")
    public String updateArticleByUser(@PathVariable("authorId") String authorId, @PathVariable("bid") String bid, Model model) {
//        CkqnUser user = (CkqnUser)session.getAttribute("loginUser");
        QueryWrapper<CkqnBlog> wrapper = new QueryWrapper<>();
        //  查询uid
        CkqnBlog blog = ckqnBlogService.getOne(wrapper.eq("bid", bid));
        System.out.println(authorId + " " + bid);
        // 2.查询作者
        if (!blog.getAuthorId().equals(authorId)) {
            System.out.println("对不起,你在非法编辑");
            //  直接注销账号
            return "redirect:/index.html";
        }
        // 3. 存放文章
        model.addAttribute("blog", blog);
        //  4.没有重定向
        return "WriteCenter/update";
    }

    //    修改的操作
    @PostMapping("/toupdate")
    public String editor(CkqnBlog blog) {
        QueryWrapper<CkqnBlog> wrapper = new QueryWrapper<>();
        System.out.println(blog);
        CkqnBlog queryBlog = ckqnBlogService.getOne(wrapper.eq("bid", blog.getBid()));
        queryBlog.setTitle(blog.getTitle());
        queryBlog.setCategoryId(blog.getCategoryId());
        queryBlog.setContent(blog.getContent());
        boolean b = ckqnBlogService.updateById(queryBlog);
        if (b) {
            return "tipSuccess";
        }
        return "tipFalse";

    }
}


3.文章展示

(1).前端页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
    <meta charset="UTF-8">
    <title>金橘社区-文章展示</title>
    <link rel="stylesheet" th:href="@{/editor.md/css/examples/style.css}" />
    <link rel="stylesheet" th:href="@{/editor.md/css/editormd.css}" />
    <link rel="shortcut icon" href="https://pandao.github.io/editor.md/favicon.ico" type="image/x-icon" />
    <script th:src="@{/Jquery/jquery-3.6.1.js}"></script>
    <link rel="stylesheet" th:href="@{/css/commons.css}">
    <link rel="stylesheet" th:href="@{/css/blog_detail.css}">
    <link rel="stylesheet" th:href="@{/layui/css/layui.css}" media="all">
    <style>
        .arrow{
            border: 9px solid transparent;
            border-bottom-color: #3DA0DB;
            width: 0px;
            height: 0px;
            top:0px
        }
        .stick{
            width: 8px;
            height: 14px;
            border-radius: 1px;
            background-color: #3DA0DB;
            top:15px;
        }
        #back_top div{
            position: absolute;
            margin: auto;
            right: 0px;
            left: 0px;
        }
        #back_top{
            background-color: #dddddd;
            height: 38px;
            width: 38px;
            border-radius: 3px;
            display: block;
            cursor: pointer;
            position: fixed;
            right: 50px;
            bottom: 100px;
            display: none;
        }
    </style>
</head>
<body>
<div class="top-search" style="margin-top: 12px;">
    <a type="button" class="layui-btn layui-btn-primary1 layui-btn-lg" style="margin-top: 42px;margin-left: 1px;"
           th:href="@{/MyArticals.html}" ><i class="layui-icon layui-icon-return"
                                                                  style="font-size: 20px; color: #1E9FFF;"></i><i
            style="color: #0e0c0d;font-family: 微软雅黑;font-weight: bold">文章管理</i></a>
</div>
<span class="js-cursor-container"></span>
<div id="article"></div>
<div id="back_top">
    <div class="arrow"></div>
    <div class="stick"></div>
</div>
<!-- .container 作为页面的版心 -->
<div class="container">
    <!-- 左侧个人信息 -->
    <div class="left">
        <!-- 整个用户信息区 -->
        <div class="card">
            <img  th:src="@{/img/login.png}" alt="">
            <h3 th:text="${article.getAuthorName()}"></h3>
            <a href="#">github 地址</a>
            <div class="counter">
                <span>文章</span>
                <span>分类</span>
            </div>
            <div class="counter">
                <span>X</span>
                <span>X</span>
            </div>
        </div>
    </div>
    <!-- 右侧内容详情 -->
    <div class="right" style="overflow: auto">
        <!-- 包裹整个博客的内容详情 -->
        <div class="blog-content">
            <h3 style="color: #e8136f" th:text="${article.title}"></h3>
            <div class="date" th:text="${#dates.format(article.getGmtCreate(),'yyyy-MM-dd HH:mm:ss')}"></div>
<!--            <h2 style="align-content: center" th:text="${article.authorName}"></h2>-->
    <div id="layout">
    <div id="test-editormd">
                <textarea style="display:none;" th:text="${article.content}"></textarea>
    </div>
</div>
</div>
</div>
</div>
<script th:src="@{/editor.md/examples/js/jquery.min.js}"></script>
<script th:src="@{/editor.md/lib/marked.min.js}"></script>
<script th:src="@{/editor.md/lib/prettify.min.js}"></script>
<script th:src="@{/editor.md/lib/raphael.min.js}"></script>
<script th:src="@{/editor.md/lib/underscore.min.js}"></script>
<script th:src="@{/editor.md/lib/sequence-diagram.min.js}"></script>
<script th:src="@{/editor.md/lib/flowchart.min.js}"></script>
<script th:src="@{/editor.md/lib/jquery.flowchart.min.js}"></script>
<script th:src="@{/editor.md/editormd.js}"></script>
<script type="text/javascript">

    var testEditor;

    $(function () {
        testEditor = editormd.markdownToHTML("test-editormd", {
            width: "90%",
            height: 700,
            path: "/editor.md/lib/",
            preview: true,
            watch: true,
            editor: false,

        })
    })
    ! function (e, t, a) {
        function r() {
            for (var e = 0; e < s.length; e++) s[e].alpha <= 0 ? (t.body.removeChild(s[e].el), s.splice(e, 1)) : (s[
                e].y--, s[e].scale += .004, s[e].alpha -= .013, s[e].el.style.cssText = "left:" + s[e].x +
                "px;top:" + s[e].y + "px;opacity:" + s[e].alpha + ";transform:scale(" + s[e].scale + "," + s[e]
                    .scale + ") rotate(45deg);background:" + s[e].color + ";z-index:99999");
            requestAnimationFrame(r)
        }

        function n() {
            var t = "function" == typeof e.onclick && e.onclick;
            e.onclick = function (e) {
                t && t(), o(e)
            }
        }

        function o(e) {
            var a = t.createElement("div");
            a.className = "heart", s.push({
                el: a,
                x: e.clientX - 5,
                y: e.clientY - 5,
                scale: 1,
                alpha: 1,
                color: c()
            }), t.body.appendChild(a)
        }

        function i(e) {
            var a = t.createElement("style");
            a.type = "text/css";
            try {
                a.appendChild(t.createTextNode(e))
            } catch (t) {
                a.styleSheet.cssText = e
            }
            t.getElementsByTagName("head")[0].appendChild(a)
        }

        function c() {
            return "rgb(" + ~~(255 * Math.random()) + "," + ~~(255 * Math.random()) + "," + ~~(255 * Math
                .random()) + ")"
        }
        var s = [];
        e.requestAnimationFrame = e.requestAnimationFrame || e.webkitRequestAnimationFrame || e
            .mozRequestAnimationFrame || e.oRequestAnimationFrame || e.msRequestAnimationFrame || function (e) {
            setTimeout(e, 1e3 / 60)
        }, i(
            ".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"
        ), n(), r()
    }(window, document);

    //-----------------------------
    (function fairyDustCursor() {

        var possibleColors = ["#D61C59", "#E7D84B", "#1B8798"]
        var width = window.innerWidth;
        var height = window.innerHeight;
        var cursor = { x: width / 2, y: width / 2 };
        var particles = [];

        function init() {
            bindEvents();
            loop();
        }

        // Bind events that are needed
        function bindEvents() {
            document.addEventListener('mousemove', onMouseMove);
            window.addEventListener('resize', onWindowResize);
        }

        function onWindowResize(e) {
            width = window.innerWidth;
            height = window.innerHeight;
        }

        function onMouseMove(e) {
            cursor.x = e.clientX;
            cursor.y = e.clientY;

            addParticle(cursor.x, cursor.y, possibleColors[Math.floor(Math.random() * possibleColors.length)]);
        }

        function addParticle(x, y, color) {
            var particle = new Particle();
            particle.init(x, y, color);
            particles.push(particle);
        }

        function updateParticles() {

            // Updated
            for (var i = 0; i < particles.length; i++) {
                particles[i].update();
            }

            // Remove dead particles
            for (var i = particles.length - 1; i >= 0; i--) {
                if (particles[i].lifeSpan < 0) {
                    particles[i].die();
                    particles.splice(i, 1);
                }
            }

        }

        function loop() {
            requestAnimationFrame(loop);
            updateParticles();
        }

        /**
         * Particles
         */

        function Particle() {

            this.character = "*";
            this.lifeSpan = 120; //ms
            this.initialStyles = {
                "position": "fixed",
                "display": "inline-block",
                "top": "0px",
                "left": "0px",
                "pointerEvents": "none",
                "touch-action": "none",
                "z-index": "10000000",
                "fontSize": "25px",
                "will-change": "transform"
            };

            // Init, and set properties
            this.init = function (x, y, color) {

                this.velocity = {
                    x: (Math.random() < 0.5 ? -1 : 1) * (Math.random() / 2),
                    y: 1
                };

                this.position = { x: x + 10, y: y + 10 };
                this.initialStyles.color = color;

                this.element = document.createElement('span');
                this.element.innerHTML = this.character;
                applyProperties(this.element, this.initialStyles);
                this.update();

                document.querySelector('.js-cursor-container').appendChild(this.element);
            };

            this.update = function () {
                this.position.x += this.velocity.x;
                this.position.y += this.velocity.y;
                this.lifeSpan--;

                this.element.style.transform = "translate3d(" + this.position.x + "px," + this.position.y + "px, 0) scale(" + (this.lifeSpan / 120) + ")";
            }

            this.die = function () {
                this.element.parentNode.removeChild(this.element);
            }

        }

        /**
         * Utils
         */

        // Applies css `properties` to an element.
        function applyProperties(target, properties) {
            for (var key in properties) {
                target.style[key] = properties[key];
            }
        }

        if (!('ontouchstart' in window || navigator.msMaxTouchPoints)) init();
    })();
    $(function(){

        $(window).scroll(function(){  //只要窗口滚动,就触发下面代码

            var scrollt = document.documentElement.scrollTop + document.body.scrollTop; //获取滚动后的高度

            if( scrollt >200 ){  //判断滚动后高度超过200px,就显示

                $("#back_top").fadeIn(400); //淡入

            }else{

                $("#back_top").stop().fadeOut(400); //如果返回或者没有超过,就淡出.必须加上stop()停止之前动画,否则会出现闪动

            }

        });

        $("#back_top").click(function(){ //当点击标签的时候,使用animate在200毫秒的时间内,滚到顶部

            $("html,body").animate({scrollTop:"0px"},200);

        });

    });

</script>
</body>
</html>

(2).后端页面

package com.jsxs.kumquat.controller;


import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jsxs.kumquat.pojo.CkqnBlog;
import com.jsxs.kumquat.pojo.CkqnUser;
import com.jsxs.kumquat.service.CkqnBlogService;
import com.jsxs.kumquat.utils.FileUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.UUID;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author 吉士先生
 * @since 2023-04-09
 */
@Controller
@RequestMapping("/article")
public class CkqnBlogController {
    @Resource
    CkqnBlogService ckqnBlogService;
    @Resource
    HttpSession session;
    // 文章上传
    @RequestMapping("/publish")
    public String publishArticle(CkqnBlog article) {
        CkqnUser user = (CkqnUser) session.getAttribute("loginUser");
        // 1.作者信息
        article.setAuthorId(user.getUid());
        article.setAuthorName(user.getUsername());
        article.setAuthorAvatar(user.getAvatar());
        // 2.博客ID
        String replace = UUID.randomUUID().toString().replace("-", "");
        article.setBid(replace);
        if (article.getTitle() == null) {
            System.out.println("标题为空?????????");
        }
        boolean res = ckqnBlogService.save(article);
        if (res) {
            return "tipSuccess";
        }
        return "tipFalse";
    }
    // 文件上传
    @RequestMapping("/image/upload")
    @ResponseBody
    public JSONObject imageUpload(@RequestParam("editormd-image-file") MultipartFile image) {
        JSONObject jsonObject = new JSONObject();
        if (image != null) {
            String path = FileUtils.uploadFile(image);
//            回调给 editor
            System.out.println(path);
            jsonObject.put("url", path);
            jsonObject.put("success", 1);
            jsonObject.put("message", "upload success!");
            return jsonObject;
        }
        jsonObject.put("success", 0);
        jsonObject.put("message", "upload error!");
        return jsonObject;
    }

    //  1.一篇详细文章
    @RequestMapping("/get/{id}")
    public ModelAndView getArticleById(@PathVariable(name = "id") int id) {
        ModelAndView modelAndView = new ModelAndView();
        CkqnBlog article = ckqnBlogService.getById(id);

        modelAndView.setViewName("WriteCenter/article");
        if (article == null) {
            modelAndView.addObject("article", new CkqnBlog());
        }
        modelAndView.addObject("article", article);
        return modelAndView;
    }

    // 开始修改
    @RequestMapping("/update/editor/{authorId}/{bid}")
    public String updateArticleByUser(@PathVariable("authorId") String authorId, @PathVariable("bid") String bid, Model model) {
//        CkqnUser user = (CkqnUser)session.getAttribute("loginUser");
        QueryWrapper<CkqnBlog> wrapper = new QueryWrapper<>();
        //  查询uid
        CkqnBlog blog = ckqnBlogService.getOne(wrapper.eq("bid", bid));
        System.out.println(authorId + " " + bid);
        // 2.查询作者
        if (!blog.getAuthorId().equals(authorId)) {
            System.out.println("对不起,你在非法编辑");
            //  直接注销账号
            return "redirect:/index.html";
        }
        // 3. 存放文章
        model.addAttribute("blog", blog);
        //  4.没有重定向
        return "WriteCenter/update";
    }

}

4.Aax 密码验证

需要引入js- 一个都不能变,注意路径

    <link rel="stylesheet" th:href="@{/editor.md/css/examples/style.css}" />
    <link rel="stylesheet" th:href="@{/editor.md/css/editormd.css}" />
    <link rel="shortcut icon" href="https://pandao.github.io/editor.md/favicon.ico" type="image/x-icon" />
    <script th:src="@{/Jquery/jquery-3.6.1.js}"></script>
    
<script th:src="@{/editor.md/examples/js/jquery.min.js}"></script>
<script th:src="@{/editor.md/lib/marked.min.js}"></script>
<script th:src="@{/editor.md/lib/prettify.min.js}"></script>
<script th:src="@{/editor.md/lib/raphael.min.js}"></script>
<script th:src="@{/editor.md/lib/underscore.min.js}"></script>
<script th:src="@{/editor.md/lib/sequence-diagram.min.js}"></script>
<script th:src="@{/editor.md/lib/flowchart.min.js}"></script>
<script th:src="@{/editor.md/lib/jquery.flowchart.min.js}"></script>
<script th:src="@{/editor.md/editormd.js}"></script>

文章主题部分

    <div id="test-editormd">
                <textarea style="display:none;" th:text="${article.content}"></textarea>
    </div>

JS

<script type="text/javascript">

    var testEditor;

    $(function () {
        testEditor = editormd.markdownToHTML("test-editormd", {
            width: "90%",
            height: 700,
            path: "/editor.md/lib/",
            preview: true,
            watch: true,
            editor: false,

        })
    })
    ! function (e, t, a) {
        function r() {
            for (var e = 0; e < s.length; e++) s[e].alpha <= 0 ? (t.body.removeChild(s[e].el), s.splice(e, 1)) : (s[
                e].y--, s[e].scale += .004, s[e].alpha -= .013, s[e].el.style.cssText = "left:" + s[e].x +
                "px;top:" + s[e].y + "px;opacity:" + s[e].alpha + ";transform:scale(" + s[e].scale + "," + s[e]
                    .scale + ") rotate(45deg);background:" + s[e].color + ";z-index:99999");
            requestAnimationFrame(r)
        }

        function n() {
            var t = "function" == typeof e.onclick && e.onclick;
            e.onclick = function (e) {
                t && t(), o(e)
            }
        }

        function o(e) {
            var a = t.createElement("div");
            a.className = "heart", s.push({
                el: a,
                x: e.clientX - 5,
                y: e.clientY - 5,
                scale: 1,
                alpha: 1,
                color: c()
            }), t.body.appendChild(a)
        }

        function i(e) {
            var a = t.createElement("style");
            a.type = "text/css";
            try {
                a.appendChild(t.createTextNode(e))
            } catch (t) {
                a.styleSheet.cssText = e
            }
            t.getElementsByTagName("head")[0].appendChild(a)
        }

        function c() {
            return "rgb(" + ~~(255 * Math.random()) + "," + ~~(255 * Math.random()) + "," + ~~(255 * Math
                .random()) + ")"
        }
        var s = [];
        e.requestAnimationFrame = e.requestAnimationFrame || e.webkitRequestAnimationFrame || e
            .mozRequestAnimationFrame || e.oRequestAnimationFrame || e.msRequestAnimationFrame || function (e) {
            setTimeout(e, 1e3 / 60)
        }, i(
            ".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"
        ), n(), r()
    }(window, document);
    </script>

全体文章

package com.jsxs.kumquat.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author Jsxs
 * @Date 2023/4/10 17:07
 * @PackageName:com.jsxs.kumquat.controller
 * @ClassName: AjaxController
 * @Description: TODO
 * @Version 1.0
 */

@RestController
public class AjaxController {
    @RequestMapping("/a3")
    public String a3(String name,String pwd){
        String msg="";
        System.out.println(name);
        System.out.println(pwd);
        if (name!=null){
            if ("吉士先生".equals(name)){
                msg="OK";
            }else {
                msg="Error";
            }
        }
        if (pwd!=null){
            if ("121788".equals(pwd)){
                msg="OK";
            }else {
                msg="Error";
            }
        }
        return msg;
    }
}

以上可以实现异步登入判断

(三)、知识点新发现

1. template包中创建包静态资源路径一样.

在这里插入图片描述

2. SpringBoot自定义400、500错误。只需要在template包下创建error包即可。

在这里插入图片描述

3. 加入我们要使用mybatis-plus那么条件构造其实际上就是对SQL的拼接操作。构造器的泛型是: 实体类

    //1. 通过账户UserUid进行查找用户
    @RequestMapping("/code")
    public String SelectByUserUid(){
        // 1.定义条件构造器-> 这里的泛型是实体类
        QueryWrapper<CkqnUser> wrapper = new QueryWrapper<>();
        wrapper.eq("uid","root");
        CkqnUser one = ckqnUserService.getOne(wrapper.eq("uid", "root"));
        return ""+one;
    }

在这里插入图片描述

4.我们在验证登入操作的时候,只需要根据username进行判断即可,因为这样可以减少对数据库的一次访问

 //1. 通过账户UserUid进行查找用户 -> 可以减少对数据库的访问频次(可以减少对密码的查询)
    @PostMapping("/code")
    public String SelectByUserUid() throws Exception {
        // 1.定义条件构造器-> 这里的泛型是实体类
        QueryWrapper<CkqnUser> wrapper = new QueryWrapper<>();
        // 2.添加条件: 是否相等
        wrapper.eq("uid","root");
        // 3.执行查找数据的操作
        CkqnUser ckqnUser = ckqnUserService.getOne(wrapper.eq("uid", "root"));
        // 4.optional检测是否为空
        Optional<CkqnUser> optional = Optional.ofNullable(ckqnUser);
        // 5.假如为空直接抛出异常
        optional.orElseThrow(()->new Exception("非常抱歉出现了空指针异常!!"));
        // 6.查看密码
        String password = ckqnUser.getPassword();

        CkqnUser ckqnUser1 = ckqnUserService.getOne(wrapper.eq("password", password));
        if (ckqnUser1.equals(ckqnUser)){
            return "index";
        }else {
            return "login";
        }

(四)、金橘社区前端设计

金橘社区

1. 渐变动态背景CSS .

<style>
        body {
    margin: 0;
    padding: 0;

    height: 100vh;

    display: flex;
    justify-content: center;
    align-items: center;

    background: linear-gradient(135deg, #34ac40, #2c8ae8, #dc47cd, #e7e373);
    background-size: 500%;

    animation: bgAnimation 6s linear infinite;
}

h1 {
    color: white;
    letter-spacing: 5px;
}

@keyframes bgAnimation {
    0% {
        background-position: 0% 50%;
    }

    50% {
        background-position: 100% 50%;
    }

    100% {
        background-position: 0% 50%;
    }
}
    </style>

在这里插入图片描述

2. sleep() 休眠的工具类

    function sleep(numberMillis) {
        var now = new Date();
        var exitTime = now.getTime() + numberMillis;
        while (true) {
            now = new Date();
            if (now.getTime() > exitTime)
                return true;
        }
    }

3. 利用JS页面的跳转,我们一定要用异步跳转

 // 这里一定要异步对其进行跳转页面
                    setTimeout(()=>{
                        document.location.href="two.html"
                    },600)

4. 好看的动态背景推荐

css

/* 清除浏览器默认边距,
使边框和内边距的值包含在元素的width和height内 */

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

/* 使用flex布局,让内容垂直和水平居中 */

section {
    /* 相对定位 */
    position: relative;
    overflow: hidden;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    /* linear-gradient() 函数用于创建一个表示两种或多种颜色线性渐变的图片 */
    background: linear-gradient(to bottom, #f1f4f9, #dff1ff);
}

/* 背景颜色 */

section .color {
    /* 绝对定位 */
    position: absolute;
    /* 使用filter(滤镜) 属性,给图像设置高斯模糊*/
    filter: blur(200px);
}

/* :nth-child(n) 选择器匹配父元素中的第 n 个子元素 */

section .color:nth-child(1) {
    top: -350px;
    width: 600px;
    height: 600px;
    background: #ff359b;
}

section .color:nth-child(2) {
    bottom: -150px;
    left: 100px;
    width: 500px;
    height: 500px;
    background: #fffd87;
}

section .color:nth-child(3) {
    bottom: 50px;
    right: 100px;
    width: 500px;
    height: 500px;
    background: #00d2ff;
}

.box {
    position: relative;
}

/* 背景圆样式 */

.box .circle {
    position: absolute;
    background: rgba(255, 255, 255, 0.1);
    /* backdrop-filter属性为一个元素后面区域添加模糊效果 */
    backdrop-filter: blur(5px);
    box-shadow: 0 25px 45px rgba(0, 0, 0, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.5);
    border-right: 1px solid rgba(255, 255, 255, 0.2);
    border-bottom: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 50%;
    /* 使用filter(滤镜) 属性,改变颜色。
    hue-rotate(deg)  给图像应用色相旋转
    calc() 函数用于动态计算长度值
    var() 函数调用自定义的CSS属性值x*/
    filter: hue-rotate(calc(var(--x) * 70deg));
    /* 调用动画animate,需要10s完成动画,
    linear表示动画从头到尾的速度是相同的,
    infinite指定动画应该循环播放无限次*/
    animation: animate 10s linear infinite;
    /* 动态计算动画延迟几秒播放 */
    animation-delay: calc(var(--x) * -1s);
}

/* 背景圆动画 */

@keyframes animate {
    0%, 100%, {
        transform: translateY(-50px);
    }
    50% {
        transform: translateY(50px);
    }
}

.box .circle:nth-child(1) {
    top: -50px;
    right: -60px;
    width: 100px;
    height: 100px;
}

.box .circle:nth-child(2) {
    top: 150px;
    left: -100px;
    width: 120px;
    height: 120px;
    z-index: 2;
}

.box .circle:nth-child(3) {
    bottom: 50px;
    right: -60px;
    width: 80px;
    height: 80px;
    z-index: 2;
}

.box .circle:nth-child(4) {
    bottom: -80px;
    left: 100px;
    width: 60px;
    height: 60px;
}

.box .circle:nth-child(5) {
    top: -80px;
    left: 140px;
    width: 60px;
    height: 60px;
}

/* 登录框样式 */

.container {
    position: relative;
    width: 400px;
    min-height: 400px;
    background: rgba(255, 255, 255, 0.1);
    display: flex;
    justify-content: center;
    align-items: center;
    backdrop-filter: blur(5px);
    box-shadow: 0 25px 45px rgba(0, 0, 0, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.5);
    border-right: 1px solid rgba(255, 255, 255, 0.2);
    border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}

.form {
    position: relative;
    width: 100%;
    height: 100%;
    padding: 50px;
}

/* 登录标题样式 */

.form h2 {
    position: relative;
    color: #fff;
    font-size: 24px;
    font-weight: 600;
    letter-spacing: 5px;
    margin-bottom: 30px;
    cursor: pointer;
}

/* 登录标题的下划线样式 */

.form h2::before {
    content: "";
    position: absolute;
    left: 0;
    bottom: -10px;
    width: 0px;
    height: 3px;
    background: #fff;
    transition: 0.5s;
}

.form h2:hover:before {
    width: 53px;
}

.form .inputBox {
    width: 100%;
    margin-top: 20px;
}

/* 输入框样式 */

.form .inputBox input {
    width: 100%;
    padding: 10px 20px;
    background: rgba(255, 255, 255, 0.2);
    outline: none;
    border: none;
    border-radius: 30px;
    border: 1px solid rgba(255, 255, 255, 0.5);
    border-right: 1px solid rgba(255, 255, 255, 0.2);
    border-bottom: 1px solid rgba(255, 255, 255, 0.2);
    font-size: 16px;
    letter-spacing: 1px;
    color: #fff;
    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
}

.form .inputBox input::placeholder {
    color: #fff;
}

/* 登录按钮样式 */

.form .inputBox input[type="submit"] {
    background: #fff;
    color: #666;
    max-width: 100px;
    margin-bottom: 20px;
    font-weight: 600;
    cursor: pointer;
}

.forget {
    margin-top: 6px;
    color: #fff;
    letter-spacing: 1px;
}

.forget a {
    color: #fff;
    font-weight: 600;
    text-decoration: none;
}

html

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
    <link rel="stylesheet" href="style.css">
 
    <title>登录:微信公众号AlbertYang</title>
</head>
 
<body>
    <section>
        <!-- 背景颜色 -->
        <div class="color"></div>
        <div class="color"></div>
        <div class="color"></div>
        <div class="box">
            <!-- 背景圆 -->
            <div class="circle" style="--x:0"></div>
            <div class="circle" style="--x:1"></div>
            <div class="circle" style="--x:2"></div>
            <div class="circle" style="--x:3"></div>
            <div class="circle" style="--x:4"></div>
            <!-- 登录框 -->
            <div class="container">
                <div class="form">
                    <h2>登录</h2>
                    <form>
                        <div class="inputBox">
                            <input type="text" placeholder="姓名">
 
                        </div>
                        <div class="inputBox">
                            <input type="password" placeholder="密码">
 
                        </div>
                        <div class="inputBox">
                            <input type="submit" value="登录">
 
                        </div>
                        <p class="forget">忘记密码?<a href="#">
                                点击这里
                            </a></p>
                        <p class="forget">没有账户?<a href="#">
                                注册
                            </a></p>
                    </form>
                </div>
            </div>
        </div>
    </section>
</body>
 
</html>

在这里插入图片描述

6. 炫酷的搜索框

<!DOCTYPE html>
<html lang="en" dir="ltr">
 
<head>
    <meta charset="utf-8">
    <title> 搜索框 </title>
    <link rel="stylesheet" href="http://at.alicdn.com/t/font_1309180_m0vigzfu7y.css">
    <style type="text/css">
        .bod1 {
            /*background: -webkit-linear-gradient(to right, #f7797d, #FBD786, #C6FFDD);*/
            /*background-image: url(" 2558.jpg");*/
            /*background-size:cover;*/
            background: #aa4b6b;
            /* fallback for old browsers */
            background: -webkit-linear-gradient(to right, #3b8d99, #6b6b83, #aa4b6b);
            /* Chrome 10-25, Safari 5.1-6 */
            background: linear-gradient(to right, #3b8d99, #6b6b83, #aa4b6b);
            /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
 
 
        }
 
        .search-box {
            position: absolute;
            top: 10%;
            left: 60%;
            transform: translate(-10%, -50%);
            background: #FD2C6B;
            height: 40px;
            border-radius: 30px;
            /*圆角边框*/
            padding: 10px;
        }
 
        .search-box:hover>.search-text {
            width: 400px;
        }
 
        .search-box:hover>.search-btn {
            background: white;
            color: #26087b;
        }
 
        .search-btn {
 
            color: white;
            float: right;
            width: 40px;
            height: 40px;
            border-radius: 50%;
            background: #FD2C6B;
            display: flex;
            justify-content: center;
            align-items: center;
            transition: 0.5s;
        }
 
        .search-text {
            border: none;
            background: none;
            outline: none;
            float: left;
            padding: 0;
            color: white;
            font-size: 20px;
            font-family: "Microsoft YaHei UI Light";
            transition: 0.5s;
            line-height: 40px;
            width: 0px;
 
        }
    </style>
</head>
 
<body class="bod1">
    <div class="search-box">
        <input class="search-text" name="inputs" placeholder="在这里输入你想要搜的的东西" >
        <a class="search-btn" onclick="as()">
            <i class="iconfont iconchazhao"></i>
        </a>
    </div>
</body>
<script>
   function as() {
   let e = document.getElementsByClassName('search-text').inputs.value
   window.location.href = `https://www.baidu.com/s?wd=${e}`
    console.log("fsfs",e)
   }
</script>
 
</html>

在这里插入图片描述

7. 返回顶部

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>doc</title>
  <style>
    .arrow{
      border: 9px solid transparent;
      border-bottom-color: #3DA0DB;
      width: 0px;
      height: 0px;
      top:0px
    }
    .stick{
      width: 8px;
      height: 14px;
      border-radius: 1px;
      background-color: #3DA0DB;
      top:15px;
    }
    #back_top div{
      position: absolute;
      margin: auto;
      right: 0px;
      left: 0px;
    }
    #back_top{
      background-color: #dddddd;
      height: 38px;
      width: 38px;
      border-radius: 3px;
      display: block;
      cursor: pointer;
      position: fixed;
      right: 50px;
      bottom: 100px;
      display: none;
    }
  </style>
</head>
<body>




<div id="article"></div>
<div id="back_top">
  <div class="arrow"></div>
  <div class="stick"></div>
</div>

<script src="http://cdn.staticfile.org/jquery/1.11.1-rc2/jquery.min.js"></script>
<script>
  $(function(){
    for(var i =0 ;i <100;i++){
      $("#article").append("<p>xxxxxxxxxx<br></p>")
    }

  })
</script>
<script>
  $(function(){

    $(window).scroll(function(){  //只要窗口滚动,就触发下面代码

      var scrollt = document.documentElement.scrollTop + document.body.scrollTop; //获取滚动后的高度

      if( scrollt >200 ){  //判断滚动后高度超过200px,就显示

        $("#back_top").fadeIn(400); //淡入

      }else{

        $("#back_top").stop().fadeOut(400); //如果返回或者没有超过,就淡出.必须加上stop()停止之前动画,否则会出现闪动

      }

    });

    $("#back_top").click(function(){ //当点击标签的时候,使用animate在200毫秒的时间内,滚到顶部

      $("html,body").animate({scrollTop:"0px"},200);

    });

  });
</script>
</body>
</html>

在这里插入图片描述

8. 特效烟花点击

<span class="js-cursor-container"></span>
<!-- 网页鼠标点击特效(爱心) -->
<script>
  ! function (e, t, a) {
  function r() {
    for (var e = 0; e < s.length; e++) s[e].alpha <= 0 ? (t.body.removeChild(s[e].el), s.splice(e, 1)) : (s[
            e].y--, s[e].scale += .004, s[e].alpha -= .013, s[e].el.style.cssText = "left:" + s[e].x +
            "px;top:" + s[e].y + "px;opacity:" + s[e].alpha + ";transform:scale(" + s[e].scale + "," + s[e]
                    .scale + ") rotate(45deg);background:" + s[e].color + ";z-index:99999");
    requestAnimationFrame(r)
  }

  function n() {
  var t = "function" == typeof e.onclick && e.onclick;
  e.onclick = function (e) {
  t && t(), o(e)
}
}

  function o(e) {
  var a = t.createElement("div");
  a.className = "heart", s.push({
  el: a,
  x: e.clientX - 5,
  y: e.clientY - 5,
  scale: 1,
  alpha: 1,
  color: c()
}), t.body.appendChild(a)
}

  function i(e) {
  var a = t.createElement("style");
  a.type = "text/css";
  try {
  a.appendChild(t.createTextNode(e))
} catch (t) {
  a.styleSheet.cssText = e
}
  t.getElementsByTagName("head")[0].appendChild(a)
}

  function c() {
  return "rgb(" + ~~(255 * Math.random()) + "," + ~~(255 * Math.random()) + "," + ~~(255 * Math
  .random()) + ")"
}
  var s = [];
  e.requestAnimationFrame = e.requestAnimationFrame || e.webkitRequestAnimationFrame || e
  .mozRequestAnimationFrame || e.oRequestAnimationFrame || e.msRequestAnimationFrame || function (e) {
  setTimeout(e, 1e3 / 60)
}, i(
  ".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"
  ), n(), r()
}(window, document);

//-----------------------------
  (function fairyDustCursor() {

  var possibleColors = ["#D61C59", "#E7D84B", "#1B8798"]
  var width = window.innerWidth;
  var height = window.innerHeight;
  var cursor = { x: width / 2, y: width / 2 };
  var particles = [];

  function init() {
  bindEvents();
  loop();
}

  // Bind events that are needed
  function bindEvents() {
  document.addEventListener('mousemove', onMouseMove);
  window.addEventListener('resize', onWindowResize);
}

  function onWindowResize(e) {
  width = window.innerWidth;
  height = window.innerHeight;
}

  function onMouseMove(e) {
  cursor.x = e.clientX;
  cursor.y = e.clientY;

  addParticle(cursor.x, cursor.y, possibleColors[Math.floor(Math.random() * possibleColors.length)]);
}

  function addParticle(x, y, color) {
  var particle = new Particle();
  particle.init(x, y, color);
  particles.push(particle);
}

  function updateParticles() {

  // Updated
  for (var i = 0; i < particles.length; i++) {
  particles[i].update();
}

  // Remove dead particles
  for (var i = particles.length - 1; i >= 0; i--) {
  if (particles[i].lifeSpan < 0) {
  particles[i].die();
  particles.splice(i, 1);
}
}

}

  function loop() {
  requestAnimationFrame(loop);
  updateParticles();
}

  /**
   * Particles
   */

  function Particle() {

  this.character = "*";
  this.lifeSpan = 120; //ms
  this.initialStyles = {
  "position": "fixed",
  "display": "inline-block",
  "top": "0px",
  "left": "0px",
  "pointerEvents": "none",
  "touch-action": "none",
  "z-index": "10000000",
  "fontSize": "25px",
  "will-change": "transform"
};

  // Init, and set properties
  this.init = function (x, y, color) {

  this.velocity = {
  x: (Math.random() < 0.5 ? -1 : 1) * (Math.random() / 2),
  y: 1
};

  this.position = { x: x + 10, y: y + 10 };
  this.initialStyles.color = color;

  this.element = document.createElement('span');
  this.element.innerHTML = this.character;
  applyProperties(this.element, this.initialStyles);
  this.update();

  document.querySelector('.js-cursor-container').appendChild(this.element);
};

  this.update = function () {
  this.position.x += this.velocity.x;
  this.position.y += this.velocity.y;
  this.lifeSpan--;

  this.element.style.transform = "translate3d(" + this.position.x + "px," + this.position.y + "px, 0) scale(" + (this.lifeSpan / 120) + ")";
}

  this.die = function () {
  this.element.parentNode.removeChild(this.element);
}

}

  /**
   * Utils
   */

  // Applies css `properties` to an element.
  function applyProperties(target, properties) {
  for (var key in properties) {
  target.style[key] = properties[key];
}
}

  if (!('ontouchstart' in window || navigator.msMaxTouchPoints)) init();
})();
</script>

在这里插入图片描述

9. 前端引入 markdown编辑器 ---- 一定要和html处于同级目录下.

[Editor.md - 开源在线 Markdown 编辑器 (pandao.github.io)](https://pandao.github.io/editor.md/)

首先我们必须先要打开上面的网站: 然后点击安装下载: 就会跳转到一个Github项目中。安装一个压缩包

在这里插入图片描述

然后解压到我们的项目中:

在这里插入图片描述

    <link rel="stylesheet" href="editor.md/css/editormd.min.css">
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="editor.md/lib/marked.min.js"></script>
    <script src="editor.md/lib/prettify.min.js"></script>
    <script src="editor.md/editormd.js"></script>
    <!-- 正文:  -->
<div id="editor">

</div>
<script>
    var editor = editormd("editor", {
        // 这里的尺寸必须在这里设置,设置样式会被 editormd 自动覆盖
        width: "100%",
        // 设置高度
        height: "500px",
        // 编辑器中初始内容
        markdown: "# 在这里写下一篇博客",
        // 指定插件路径
        path: "editor.md/lib/"
    });
</script>

在这里插入图片描述

在这里插入图片描述

10. 百度搜索框

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Serach</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .top-search {
      width: 680px;
      height: 45px;
      margin: 30px auto;

    }

    .search-box {
      display: flex;
      position: relative;
    }

    .search-left {
      width: 545px;
      height: 45px;
      border: 2px solid rgb(196, 199, 206);
      border-top-left-radius: 10px;
      border-bottom-left-radius: 10px;
      outline-color: rgb(78, 110, 242);
    }

    .icon-xiangji {
      position: absolute;
      right: 150px;
      top: 12px;
      font-size: 24px;
      color: rgb(196, 199, 206);
    }

    .search-right {
      color: #fff;
      font-size: 18px;
      width: 110px;
      height: 49px;
      border: 0px;
      border-top-right-radius: 10px;
      border-bottom-right-radius: 10px;
      background-color: rgb(78, 110, 242);
    }
            #su:hover{
            background: #14dc99;
        }

  </style>
</head>
<body>
<form action="mainMenu.html">
<div class="top-img"></div>
<div class="top-search">
  <div class="search-box">
      <input type="text" name="search" class="search-left">
      <span class="iconfont icon-xiangji"></span>
      <input class="search-right" type="subbmit" name="btn" id="su" value='发表文章'>
  </div>
</div>
</form>
</body>
</html>

在这里插入图片描述

11. 二维码弹窗!!!

<!DOCTYPE html>
<html>
<head>
  <title>test1</title>
  <meta charset="UTF-8">
  <%--注意引用和地址--%>
  <script src="static/Jquery/jquery-3.6.1.js"></script>
  <script src="static/layui/layui.js" charset="utf-8"></script>
  <script src="https://static.runoob.com/assets/qrcode/qrcode.min.js"></script>
  <link rel="stylesheet" href="static/layui/css/layui.css"  media="all">
</head>
<body>

<div align="center">
  <button type="button" class="layui-btn layui-btn-normal layui-btn-radius" onclick="skipHandle()">预览</button>
</div>

<div id="code" style="display: none;">
  <div id="qrcode" style="margin-left: 75px;margin-top: 20px">
   <h1 style="color: #e8136f">你好</h1>
  </div>
</div>

<script>

  layui.use(['layer'], function () {
    var layer = layui.layer
  });

  // 设置要生成二维码的链接
  new QRCode(document.getElementById("qrcode"), {
    text: "https://img-home.csdnimg.cn/images/20230407093553.jpg", //设置二维码内容
    canvas: "table", //设置渲染方式
    width: 250,
    height: 250
  });

  //预览等弹出框
  function skipHandle() {
    layer.open({
      type: 1,
      title: "bug_producter的博客",//标题
      area: ['400px', '400px'],
      content: $('#code').html(),
    });
  }

</script>
</body>
</html>

在这里插入图片描述

12. 文本框不能为空格的属性,一个属性就可以

οnkeyup="this.value=this.value.replace(/\s+/g,'')"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/432504.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows安装RedisJSON(无需编译)

文章目录 Windows安装RedisJSON下载解压配置文件启动服务启动客户端 Windows安装RedisJSON 下载 打开网址 https://github.com/zkteco-home/RedisJson。 在网页的右上角&#xff0c;点击“Code”按钮&#xff0c;然后选择“Download ZIP”以下载最新版本的RedisJSON。 网盘 …

C6678-控制GPIO输入/输出

C6678-控制GPIO输入/输出 术语寄存器起始地址原理输入输出测试中断功能原理中断原理框图芯片中断控制器原理框图内核中断控制器原理框图中断路由架构一级中断表二级中断表CIC0二级中断CIC1二级中断CIC2二级中断CIC3 中断演示代码参考资料 术语 NMI&#xff1a; 不可屏蔽中断CI…

6、在vscode上利用cmake创建第一个简单C++程序

文章目录 &#xff08;1&#xff09;前期准备工作&#xff1a;即安装对应的环境1&#xff09;在vscode上安装插件&#xff1a;C/C、Cmake、CMake tools2&#xff09;安装Cmake环境&#xff08;这是在前面博客提到的已经安装好gcc等环境的前提下进行的&#xff09; &#xff08;…

Springboot基础学习之(二十二):异步任务和邮件任务

方向一&#xff1a;高效学习方法分享 我认为学习的最好的办法就是做笔记:本人特别喜欢在网上学习一些课堂外的知识&#xff0c;但是如果你没有及时的复习&#xff0c;要想找到自己想要的知识该怎么办呢&#xff1f;对&#xff0c;就是做笔记我在csdn这个app发的所有内容都是笔记…

Android UI布局优化之include、merge与ViewStub标签的巧用方法

前言 在开发中UI布局是我们都会遇到的问题&#xff0c;随着UI越来越多&#xff0c;布局的重复性、复杂度也会随之增长。 相信大家经常听到include、merge、ViewStub这样的标签&#xff0c;官方也提到这三种布局可用于布局的优化。今天就介绍下这三种布局的使用&#xff0c;记…

SRv6项目实践(一):环境与工具介绍

在一切开始之前&#xff0c;首先介绍一下我们要做什么&#xff0c;做这个要有什么基础&#xff0c;以及实现的环境 1&#xff0c;实验目标与实验基础 我们要在图下图所示的拓扑中&#xff0c;完成在如以下拓扑所示的网络中&#xff0c;配合ONOS实现基本的L2L3转发以及SRv6&am…

港联证券|券商再迎利好!这一比例大幅下调,释放300亿资金

券商利好接二连三。 4月10日&#xff0c;即日起下调证券公司转融通保证金份额。资信优质的公司&#xff0c;保证金份额由20%下调至5%&#xff1b;资信杰出的公司&#xff0c;由20%下调至10%&#xff1b;其余公司由25%下调至15%。中证金融预计&#xff0c;保证金份额下调后&…

Linux系统之tomcat的安装方法

Linux系统之tomcat的安装方法一、tomcat介绍1.tomcat简介2.tomcat官网二、本次环境规划三、安装jdk1.下载jdk包2.安装jdk3.检查jdk版本四、安装tomcat1.下载tomcat2.解压tomcat软件包3.设置环境变量4.查看tomcat版本五、启动tomcat1.启动tomcat服务2.检查tomcat服务状态3.访问t…

原来情感可以这样影响用户体验设计

&#x1f525;情绪的基本情况 Emotion&#xff1a;即刻的生理反应&#xff0c; Feeling&#xff1a;物理的或者心理上的&#xff0c;是emotion经过思考后的 Mood&#xff1a;持续时间更长&#xff0c;是一种状态&#xff0c;受到很多因素影响&#xff08;天气、睡眠&#x…

92-TCP三次握手及TCP四次挥手

TCP三次握手及TCP四次挥手1.tcp三次握手(1)tcp的特点(2)tcp三次握手发生在什么阶段(3)tcp协议报头(4)tcp三次握手的流程2.tcp四次挥手(1)tcp四次挥手发生在什么阶段(2)tcp四次挥手的流程(3)能不能将服务器发端发送的ACK和FIN放在一起发送呢1.tcp三次握手 (1)tcp的特点 TCP 协…

十六、市场活动:查看市场活动明细(二)

功能需求 点击市场活动名称链接,跳转到明细页面,查看市场活动明细 -市场活动的基本信息 -市场活动下所有的备注信息 功能分析 流程图 代码实现 一、ActivityRemarkMapper 1.ActivityRemarkMapper接口 /*** 根据市场活动id查询备注*/List<ActivityRemark> selectActivi…

贪吃蛇小项目

1.总体程序 #include <curses.h> #include <stdlib.h> #include <pthread.h> #include <math.h> #include <time.h> struct Snake //贪吃蛇身子节点 {char node; //节点序号int row; //行坐标int column; //列坐标stru…

探索实践低光照场景下YOLOv5s模型上限,融合CBAM注意力机制开发构建基于改进YOLOv5s的低光照条件下目标检测识别分析系统

在现实生活场景里面&#xff0c;很多场景下光线光照条件都是比较差的&#xff0c;比如夜晚、室内等&#xff0c;这时候以往的目标检测模型是否还能够胜任我们所需的目标检测任务呢&#xff1f;这里主要的想法就是基于地光线条件下的数据集来开发构建目标检测系统&#xff0c;探…

Flowable6.x导出/查看/跟踪流程图(续)

书接上回 项目源码仓库 无论是待办、已办&#xff0c;亦或是流转中、已结束的流程实例&#xff0c;通过使用JS绘制SVG格式的交互式流程图&#xff0c;与以上篇博文中三种方式相比&#xff0c;在效果上都具有明显优势。 运行效果如下图所示&#xff1a; 整合、改造Flowable中…

110.【23种设计模式--创建者模式】

Java 23种设计模式 (一)、设计模式相关内容介绍1.软件设计模式概述(1).软件设计模式的产生背景(2).软件设计模式的概念(3).学习设计模式的重要性(4).设计模式分类 2.UML图(1).类图概述(2).类图的作用(3).类图表示法 3.软件设计原则(1).开闭原则 (重写不修改)(2).里氏代换原则 (…

node的安装与卸载

node的安装与卸载 今天遇到个问题 使用npm命令时报错显示栈溢出&#xff0c;所以将node重装了一下&#xff0c; 一.卸载node&#xff1a; 1.在程序与功能里卸载node.js&#xff0c;然后删除node相关文件夹&#xff0c;此次安装我将node安装在C盘里&#xff0c;将他的全局缓存…

10万字信用大数据一体化监管平台建设方案word

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除。 1.1、 系统主要功能需求分析 XX公共信用信息管理系统的主要业务流程包括信用信息资源编录管理流程、信用信息归集流程、信用信息服务流程和信用信息异议处理流程。 一.1.1…

NLP作业01:利用HMM实现词性标注

作业头 这个作业属于哪个课程自然语言处理这个作业要求在哪里利用HMM实现词性标注作业要求我在这个课程的目标实现词性标注这个作业在哪个具体方面帮助我实现目标代码实现参考文献1.隐马尔科夫模型 2.基于HMM的词性标注  3.基于HMMViterbi算法的词性标注 Python 文章目录 作…

【LeetCode: 673. 最长递增子序列的个数 | 动态规划】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

LeetCode 热题 HOT 100:从前序与中序遍历序列构造二叉树、二叉树展开为链表、二叉树中的最大路径和

LeetCode 热题 HOT 100 105. 从前序与中序遍历序列构造二叉树 题目&#xff1a; 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c; 请构造二叉树并返回其根节点。 示例 1&#xff1…