SpringBoot+网易邮箱登录注册

文章目录

  • SpringBoot+网易邮箱登录注册
    • pom.xml
    • application.yml
    • sql
    • UserEmail.java
    • UserEmailMapper.java
    • UserEmailMapper.xml
    • EmailService.java
    • UserEmailService.java
    • UserEmailServiceImpl.java
    • UserEmailController.java
    • register1.html

编写前参考

SpringBoot+网易邮箱登录注册

pom.xml

<?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.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.sin</groupId>
    <artifactId>RedisMailMessage</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <packaging>war</packaging>

    <name>RedisMailMessage</name>

    <description>RedisMailMessage</description>

    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <!--
            邮箱业务:
                用于操作邮件功能的
         -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.3.1</version>
        </dependency>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>


        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--
            对SpringBoot应用的监控
         -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--
            SpringBoot框架的启动器
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!--
            SpringBoot框架的测试库
         -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- Java提供的工具库 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.5</version>
        </dependency>




    </dependencies>

    <build>
        <plugins>
            <!--
                SpringBoot应用打包为可执行的jar文件
             -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!--
                单元测试的插件
                    配置为逃过运行测试
             -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
                <configuration>
                    <skipTests>true</skipTests>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

application.yml

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/demo
    username: root
    password: 123456
  redis:
    # 地址
    host: 192.168.226.137
    # 端口
    port: 6379
    # 密码
    password: 123456
    # 超时时间 5000毫秒
    timeout: 5000
    jedis:
    # 连接池
      pool:
      # 连接池最小空闲连接
        min-idle: 0
      # 连接池的最大空闲连接
        max-idle: 8
      # 连接池最大阻塞等待时间(使用负数表示没有限制)
        max-wait: -1
      # 连接池最大连接数(使用负数表示没有限制)
        max-active: 8

  mail:
    # 配置SMTP服务器地址
    host: smtp.126.com
    # 配置端口号465或者25
    port: 25
    # 发送者邮箱(根据自己邮箱填写)
    username: sin8023@126.com
    #  配置密码,注意是开启POP3/SMTP的授权密码(根据自己的授权密码填写)
    password: RVJJ****NTPUEHO

    properties:
      mail:
        smtp:
          auth: true
          enable: true
          ssl:
            # 设为true时 端口号设为 465 设为false时 端口号设为25
            enable: false
          socketFactoryClass: javax.net.ssl.SSLSocketFactory
        #表示开启 DEBUG 模式,这样,邮件发送过程的日志会在控制台打印出来,方便排查错误
        debug: true
    # 邮箱编码格式
    default-encoding: UTF-8
#  thymeleaf:
#    prefix: classpath:/templates/
#    suffix: .html
#    mode: HTML
#    encoding: utf-8
#    servlet.content-type: text/html
#    check-template-location: true  #检查模板路径是否存在
#    cache: false

# mybatis配置
mybatis:
  # 获取配置文件的地址
  mapper-locations: classpath:/mapper/*.xml
  # 获取实体类的地址
  type-aliases-package: com.sin.pojo
  configuration:
    # 开启驼峰命名
    map-underscore-to-camel-case: true

logging:
  level:
    org.mybatis: debug

sql

create table user_email
(
    id       int auto_increment primary key comment '主键id',
    name     varchar(20) character set utf8mb4 not null comment '用户名',
    password varchar(20) character set utf8mb4 not null comment '密码',
    email    varchar(20) character set utf8mb4 not null comment '邮箱',
    code_status int default 0 comment '邮箱验证状态 1 = 未注册 ,1 = 已经注册 其余数字为无效标识符'
)charset = utf8mb4;



insert into user_email(name,password,email,code_status) select email,'aaa' from user where email='123@qq.com';

insert into user_email(name,password,email,code_status) value ('admin','123456','123@qq.com',1);

select * from user_email where name = 'admin' and password = '123456' and code_status = 1;

UserEmail.java

package com.sin.pojo;


public class UserEmail {

  private long id;
  private String name;
  private String password;

  private String email;

  private int codeStatus;

  public UserEmail() {
  }

  public UserEmail(String name, String password, String email) {
    this.name = name;
    this.password = password;
    this.email = email;
  }

  public long getId() {
    return id;
  }

  public void setId(long id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public String getEmail() {
    return email;
  }

  public void setEmail(String email) {
    this.email = email;
  }

  public int getCode_status() {
    return codeStatus;
  }

  public void setCode_status(int codeStatus) {
    this.codeStatus = codeStatus;
  }


  @Override
  public String toString() {
    return "UserEmail{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", password='" + password + '\'' +
            ", email='" + email + '\'' +
            ", codeStatus='" + codeStatus + '\'' +
            '}';
  }
}

UserEmailMapper.java

package com.sin.mapper;

import com.sin.pojo.UserEmail;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

/**
 * @createTime 2023/10/23 15:39
 * @createAuthor SIN
 * @use  数据访问层,数据访问的核心任务
 */
@Mapper
public interface UserEmailMapper {

    /**
     * 添加数据
     * @param userEmail
     * @return
     */
    int insertUserEmail(UserEmail userEmail);


    /**
     * 根据用户名进行查找数据
     * @param userEmail
     * @return
     */
    UserEmail findUserByName(String userEmail);

    /**
     * 查询所有数据
     * @return
     */
    List<UserEmail> seletctUserEmail();

    /**
     * 根据邮箱进行查询
     * @param email
     * @return
     */
    UserEmail findAllByEmail(String email);


    /**
     * 更新数据
     * @param email
     * @return
     */
    void updateCodeStatus(String email);

    /**
     * 根据邮箱查询数据
     * @param email
     * @return
     */
    UserEmail findByEmail(String email);
}

UserEmailMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sin.mapper.UserEmailMapper">
    <!--
        resultMap通过将查询结果集中的列名和Java对象中的属性名进行映射,实现了结果集的自动映射。
        同时,它还可以解决列名和属性名不匹配的问题,支持复杂类型映射,提高了查询性能。
     -->
    <resultMap id="UserMap" type="com.sin.pojo.UserEmail">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="password" column="password"/>
        <result property="email" column="email"/>
        <result property="codeStatus" column="code_status"/>
    </resultMap>

    <!-- 添加数据 -->
    <insert id="insertUserEmail" parameterType="com.sin.pojo.UserEmail">
        insert into user_email(name,password,email,code_status)

        values (#{name},#{password},#{email},#{codeStatus})
    </insert>
    <update id="updateCodeStatus"  parameterType="com.sin.pojo.UserEmail">
        update user_email set code_status = 2 where email = #{email};
    </update>

    <!-- 根据姓名密码查询数据 -->
    <select id="findUserByName" resultMap="UserMap">
        select name from user where name = #{name} and password = #{password} and code_status = 1
    </select>



    <!-- 查询所有数据 -->
    <select id="seletctUserEmail" resultMap="UserMap">
        select * from user_email
    </select>

    <!-- code_status = 1时,表明用户已经存在但未完成注册操作 -->
    <select id="findAllByEmail" resultMap="UserMap">
        select * from user_email where email = #{email} and code_status = 1
    </select>

    <!-- code_status = 2时,表明用户已经完成注册操作可以进行登录操作 -->
    <select id="findByEmail" parameterType="string"  resultMap="UserMap">
        select * from user_email where email = #{email} and code_status = 2
    </select>


</mapper>

EmailService.java

package com.sin.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

/**
 * @createTime 2023/11/21 10:18
 * @createAuthor SIN
 * @use
 */

@Service
public class EmailService {


    @Autowired(required = false)
    private JavaMailSender mailSender;

    @Value("${spring.mail.username}")
    private String userName;


    /**
     * 发送信息邮件
     * @param to 收件人
     * @param subject 邮箱标题
     * @param content 邮箱内容
     */
    public void sendMail(String to, String subject, String content) throws MessagingException {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        //邮箱发送者
        helper.setFrom(userName);
        //收件人,可以为多个收件人,收件人之间用逗号隔开
        helper.setTo(to);
        // 邮箱标题
        helper.setSubject(subject);
        // 邮箱内容
        helper.setText(content, true);
        mailSender.send(message);
    }
}

UserEmailService.java

package com.sin.service;

import com.sin.exception.EmailAlreadyExistsException;
import com.sin.pojo.UserEmail;

import javax.mail.MessagingException;
import java.util.List;

/**
 * @createTime 2023/11/20 17:25
 * @createAuthor SIN
 * @use
 */
public interface UserEmailService {


    /**
     * 添加数据
     * @param userEmail
     * @return
     */
    int insertUserEmail(UserEmail userEmail) throws MessagingException, EmailAlreadyExistsException;


    /**
     * 根据用户名进行查找数据
     * @param userEmail
     * @return
     */
    UserEmail findUserByName(String userEmail);


    /**
     * 查询所有数据
     * @return
     */
    List<UserEmail> seletctUserEmail();

    /**
     * 根据邮箱进行查询
     * @param email
     * @return
     */
    UserEmail findAllByEmail(String email);


    /**
     * 发送验证码
     * @return
     */
    String sendCode(String email) throws MessagingException;


    /**
     * 获取验证码
     * @return
     */
    Object getCode(String email);


    /**
     * 更新数据
     * @param email
     * @return
     */
    void updateCodeStatus(String email);


    /**
     * 根据邮箱查询数据
     * @return
     */
    boolean loginUser(String email, String password);

}

UserEmailServiceImpl.java

package com.sin.service.impl;

import com.sin.mapper.UserEmailMapper;
import com.sin.pojo.UserEmail;
import com.sin.exception.EmailAlreadyExistsException;
import com.sin.service.EmailService;
import com.sin.service.UserEmailService;
import com.sin.utils.RandomCodeUtil;
import com.sin.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import java.util.List;

/**
 * @createTime 2023/11/20 17:25
 * @createAuthor SIN
 * @use
 */
@Service
public class UserEmailServiceImpl implements UserEmailService {

    @Autowired
    private UserEmailMapper userEmailMapper;


    @Autowired
    private EmailService emailService;


    @Override
    public int insertUserEmail(UserEmail userEmail) throws MessagingException, EmailAlreadyExistsException {


        // 1,查询要添加的数据如果没有数据就添加
        UserEmail allByEmail = this.findAllByEmail(userEmail.getEmail());
        if (allByEmail != null){
            throw new EmailAlreadyExistsException("该邮箱以注册,请登录");
        }else {
            System.out.println("数据添加成功");
            userEmail.setCode_status(1);
            emailService.sendMail(userEmail.getEmail(),"验证码","<a href=\"http://localhost:8080/update/"+userEmail.getEmail()+"\">激活请点击:</a>");
            return  userEmailMapper.insertUserEmail(userEmail);
        }
    }

    @Override
    public UserEmail findAllByEmail(String email) {
        return userEmailMapper.findAllByEmail(email);
    }

    @Override
    public String sendCode(String email) throws MessagingException {
        UserEmail allByEmail = this.findAllByEmail(new UserEmail().getEmail());
        return "";

    }

    @Override
    public Object getCode(String email) {
        if (email != null){
            Object o = redisUtil.get(email);
            System.out.println(o);
            return o;
        }else {
            return "未填写邮箱";
        }


    }

    @Override
    public void updateCodeStatus(String email) {
         userEmailMapper.updateCodeStatus(email);
    }

    @Override
    public boolean loginUser(String email, String password) {
        UserEmail userByName = userEmailMapper.findByEmail(email);
        return userByName != null && userByName.getPassword().equals(password);
    }


    @Override
    public UserEmail findUserByName(String userEmail) {
        return null;
    }

    @Override
    public List<UserEmail> seletctUserEmail() {
        return userEmailMapper.seletctUserEmail();
    }


}

UserEmailController.java

package com.sin.controller;

import com.sin.exception.EmailAlreadyExistsException;
import com.sin.mapper.UserEmailMapper;
import com.sin.pojo.UserEmail;
import com.sin.service.UserEmailService;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.mail.MessagingException;

/**
 * @createTime 2023/11/22 11:47
 * @createAuthor SIN
 * @use
 */
@Controller
public class UserEmailController {

    @Autowired
    private UserEmailService userEmailService;

    @GetMapping("/register")
    public String login(Model model){
        UserEmail userEmail = new UserEmail();
        model.addAttribute("userEmail",userEmail);
        // 设置成功消息
        model.addAttribute("successMessage", "邮件已发送,请注意查收");
        return "register1";
    }

    @PostMapping("/register")
    // @ModelAttribut : 将请求参数绑定到模型对象上,
    public String login(@ModelAttribute("userEmail") UserEmail userEmail, Model model) throws MessagingException {
        try{
            int result = userEmailService.insertUserEmail(userEmail); // 执行用户注册
            System.out.println(result);

        }catch (EmailAlreadyExistsException e){
            String errorMessage = e.getMessage();
            System.out.println(errorMessage);
            model.addAttribute("errorMessage",errorMessage);
        }
        return "redirect:/register";
    }

    @GetMapping("/update/{email}")
    @ResponseBody
    public String updateCodeStatus(@PathVariable("email") String email){
        userEmailService.updateCodeStatus(email);
        return "SUCCESS";
    }

    @PostMapping("/login")
    public String loginUser(@RequestParam("email") String email, @RequestParam("password") String password) {
        boolean isValid = userEmailService.loginUser(email, password);
        System.out.println(isValid);
        // 登录成功后返回到/dashboard页面
        if (isValid) {
            return "SUCCESS";
        } else {  // 登录失败返回该页面
            return "login";
        }
    }



}

register1.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录/注册</title>
    <style>
        :root {
            /* COLORS */
            --white: #e9e9e9;
            --gray: #333;
            --blue: #0367a6;
            --lightblue: #008997;

            /* RADII */
            --button-radius: 0.7rem;

            /* SIZES */
            --max-width: 758px;
            --max-height: 420px;

            font-size: 16px;
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
            Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
        }

        body {
            align-items: center;
            background-color: var(--white);
            background: url("https://res.cloudinary.com/dbhnlktrv/image/upload/v1599997626/background_oeuhe7.jpg");
            /* 决定背景图像的位置是在视口内固定,或者随着包含它的区块滚动。 */
            /* https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-attachment */
            background-attachment: fixed;
            background-position: center;
            background-repeat: no-repeat;
            background-size: cover;
            display: grid;
            height: 100vh;
            place-items: center;
        }

        .form__title {
            font-weight: 300;
            margin: 0;
            margin-bottom: 1.25rem;
        }

        .link {
            color: var(--gray);
            font-size: 0.9rem;
            margin: 1.5rem 0;
            text-decoration: none;
        }

        .container {
            background-color: var(--white);
            border-radius: var(--button-radius);
            box-shadow: 0 0.9rem 1.7rem rgba(0, 0, 0, 0.25),
            0 0.7rem 0.7rem rgba(0, 0, 0, 0.22);
            height: var(--max-height);
            max-width: var(--max-width);
            overflow: hidden;
            position: relative;
            width: 100%;
        }

        .container__form {
            height: 100%;
            position: absolute;
            top: 0;
            transition: all 0.6s ease-in-out;
        }

        .container--signin {
            left: 0;
            width: 50%;
            z-index: 2;
        }

        .container.right-panel-active .container--signin {
            transform: translateX(100%);
        }

        .container--signup {
            left: 0;
            opacity: 0;
            width: 50%;
            z-index: 1;
        }

        .container.right-panel-active .container--signup {
            animation: show 0.6s;
            opacity: 1;
            transform: translateX(100%);
            z-index: 5;
        }

        .container__overlay {
            height: 100%;
            left: 50%;
            overflow: hidden;
            position: absolute;
            top: 0;
            transition: transform 0.6s ease-in-out;
            width: 50%;
            z-index: 100;
        }

        .container.right-panel-active .container__overlay {
            transform: translateX(-100%);
        }

        .overlay {
            background-color: var(--lightblue);
            background: url("https://cdn.pixabay.com/photo/2018/08/14/13/23/ocean-3605547_1280.jpg");
            background-attachment: fixed;
            background-position: center;
            background-repeat: no-repeat;
            background-size: cover;
            height: 100%;
            left: -100%;
            position: relative;
            transform: translateX(0);
            transition: transform 0.6s ease-in-out;
            width: 200%;
        }

        .container.right-panel-active .overlay {
            transform: translateX(50%);
        }

        .overlay__panel {
            align-items: center;
            display: flex;
            flex-direction: column;
            height: 100%;
            justify-content: center;
            position: absolute;
            text-align: center;
            top: 0;
            transform: translateX(0);
            transition: transform 0.6s ease-in-out;
            width: 50%;
        }

        .overlay--left {
            transform: translateX(-20%);
        }

        .container.right-panel-active .overlay--left {
            transform: translateX(0);
        }

        .overlay--right {
            right: 0;
            transform: translateX(0);
        }

        .container.right-panel-active .overlay--right {
            transform: translateX(20%);
        }

        .btn {
            background-color: var(--blue);
            background-image: linear-gradient(90deg, var(--blue) 0%, var(--lightblue) 74%);
            border-radius: 20px;
            border: 1px solid var(--blue);
            color: var(--white);
            cursor: pointer;
            font-size: 0.8rem;
            font-weight: bold;
            letter-spacing: 0.1rem;
            padding: 0.9rem 4rem;
            text-transform: uppercase;
            transition: transform 80ms ease-in;
        }

        .form>.btn {
            margin-top: 1.5rem;
        }

        .btn:active {
            transform: scale(0.95);
        }

        .btn:focus {
            outline: none;
        }

        .form {
            background-color: var(--white);
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            padding: 0 3rem;
            height: 100%;
            text-align: center;
        }

        .input {
            background-color: #fff;
            border: none;
            padding: 0.9rem 0.9rem;
            margin: 0.5rem 0;
            width: 100%;
        }

        @keyframes show {

            0%,
            49.99% {
                opacity: 0;
                z-index: 1;
            }

            50%,
            100% {
                opacity: 1;
                z-index: 5;
            }
        }
        .error-message{
            color: red;
        }
    </style>
</head>

<body>
<div class="container right-panel-active">
    <!-- 注册 -->
    <div class="container__form container--signup">
        <form method="post" th:action="@{/register}" th:object="${userEmail}"  class="form" id="form1">

            <h2 class="form__title">注册</h2>
            <input type="text" placeholder="用户" th:field="*{name}" class="input" />
            <input type="password" placeholder="密码" th:field="*{password}" class="input" />
            <input type="email" placeholder="邮箱" th:field="*{email}" class="input" />
            <div class="error-message" th:if="${errorMessage}"> <!-- 修改变量名为 "errorMessage" -->
                <p id = "aaa" th:text="${errorMessage}"></p>
            </div>
            <button  class="btn" type="submit">注册</button>
        </form>
    </div>
    <div class="success-message" th:if="${successMessage}">
        <p th:text="${successMessage}"></p>
    </div>


    <!-- 登录 -->
    <div class="container__form container--signin">
        <form method="post" th:action="@{/login}" class="form" id="form2">
            <h2 class="form__title">登录</h2>
            <input type="email" placeholder="Email" name="email" class="input" />
            <input type="password" placeholder="Password" name="password" class="input" />
            <a href="#" class="link">忘记密码了?</a>
            <button class="btn" type="submit" >注册</button>
        </form>
    </div>

    <!-- Overlay -->
    <div class="container__overlay">
        <div class="overlay">
            <div class="overlay__panel overlay--left">
                <button class="btn" id="signIn">登录</button>
            </div>
            <div class="overlay__panel overlay--right">
                <button class="btn" id="signUp">注册</button>
            </div>
        </div>
    </div>
</div>

<script>
    const signInBtn = document.getElementById("signIn");
    const signUpBtn = document.getElementById("signUp");

    const container = document.querySelector(".container");


    signInBtn.addEventListener("click", () => {
        container.classList.remove("right-panel-active");
    });

    signUpBtn.addEventListener("click", () => {
        container.classList.add("right-panel-active");
    });

    // 获取页面元素
    const form = document.getElementById("form1");
    const errorMessage = document.getElementById("errorMessage");

    // 提交表单时,禁用按钮并显示加载状态
    form.addEventListener("submit", function() {
        const button = form.querySelector("button[type=submit]");
        button.disabled = true;
        button.innerText = "加载中...";
    });

    // 如果页面存在错误消息,则弹出消息框
    if (errorMessage) {
        alert(errorMessage.innerText);
    }

</script>
</body>

</html>

在这里插入图片描述

邮箱

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文生视频的发展史及其原理解析:从Gen2、Emu Video到PixelDance、SVD、Pika 1.0

前言 考虑到文生视频开始爆发&#xff0c;比如11月份就是文生视频最火爆的一个月 11月3日&#xff0c;Runway的Gen-2发布里程碑式更新&#xff0c;支持4K超逼真的清晰度作品(runway是Stable Diffusion最早版本的开发商&#xff0c;Stability AI则开发的SD后续版本)11月16日&a…

Python MD5加密的三种方法(可加盐)

方法一&#xff1a;MD5直接加密 import hashlibtext1123456 print(text1) mdhashlib.md5(text1.encode()) # 创建md5对象 md5pwdmd.hexdigest() # md5加密 print(md5pwd) 输出结果&#xff1a; 方法二&#xff1a;MD5盐加密&#xff0c;将盐拼接在原密码后 import ha…

轻松愉悦的验证方式:实现图片旋转验证功能

说在前面 在当今互联网时代&#xff0c;随着技术的不断进步&#xff0c;传统的验证码验证方式已经无法满足对安全性和用户体验的需求。为了应对日益狡猾的机器人和恶意攻击&#xff0c;许多网站和应用程序开始引入图形验证码&#xff0c;其中一种备受欢迎的形式就是图片旋转验证…

手机一键“触达”!VR全景助力政务服务大厅数字升级

在我们的日常生活中&#xff0c;去政务服务大厅办事&#xff0c;总是避免不了遭遇“缺一样材料”的烦恼。因此网友总是吐槽&#xff0c;办事服务窗口总是多次要求提供不同证明&#xff0c;“一会儿说要身份证&#xff0c;一会儿又说要护照”&#xff0c;每次带上服务窗口要求的…

pyqt 创建 Windows 窗口 音乐图片播放器制作

Part1&#xff1a; 介绍 在这篇文章中&#xff0c;我们将学习如何使用PyQt 库创建一个基本的窗口应用程序&#xff0c;并进行一些常见的窗口定制。我们将涵盖以下主题: 1.创建基本窗口 2.设置窗口布局 3.设置窗口名 4.实现窗口的最大化和最小化功能 5.加载图片&#xff0c;播…

enum枚举类 - Java

枚举类 一、引入二、介绍三、实现方式1、 自定义类实现枚举小结 2、 enum关键字实现枚举 四、使用enum注意事项五、练习六、enum常用方法七、练习八、enum和接口 一、引入 要求创建季节(Season)对象&#xff0c;请设计并完成。 传统方法&#xff1a; public class Enumerati…

牛客算法心得——kotori和素因子(dfs)

大家好&#xff0c;我是晴天学长&#xff0c;传智杯的题&#xff0c;一个经典的全排列找最小的问题&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1f4aa; 1) .kotori和素因子 链接&#xff1a;https://ac.nowcod…

运维知识点-openResty

openResty 企业级实战——畅购商城SpringCloud-网站首页高可用解决方案-openRestynginxlua——实现广告缓存测试企业级实战——畅购商城SpringCloud-网站首页高可用解决方案-openRestynginxlua——OpenResty 企业级实战——畅购商城SpringCloud-网站首页高可用解决方案-openRes…

鸿蒙【HarmonyOS】开发初体验

官方开发文档 依照官方开发文档进行配置&#xff0c;官方的文档很详细&#xff08;虽然有些粗糙&#xff09;。 其实只要下载了deveco studio&#xff0c;其他就按照next来就行了。配置都很清楚。 顺便提一下&#xff0c;deveco是基于intellij 的&#xff0c;体验很不错&…

Android性能优化- 从SharedPreferences到MMKV

前言 前面Android性能优化 - 从SharedPreferences跨越到DataStore一文主要介绍了DataStore的实现原理&#xff0c;以及DataStore相对于SharedPreferences的提升&#xff0c;本文主要简述MMKV相对于SharedPreferences存储的使用及优劣势&#xff0c;以及MMKV原理&#xff0c;以…

chrome 调试之 - 给微软小冰看病(无论给小冰发送什么内容都只回复“我已经开始升级啦,期待一下吧!”)

微软 Bing 搜索推出了小冰AI智能聊天模块&#xff0c;具体启用方式是用edge或chrome浏览器打开链接 cn.bing.com 后在输入框搜索任意内容&#xff0c;待搜索结果页面加载完并稍等片刻&#xff0c;页面右侧就会出现一个躲在滚动条后面的小萝莉&#xff0c;抚摸...不&#xff0c;…

elementui中table进行表单验证

<el-form :model"ruleForm" ref"ruleForm" class"demo-ruleForm"><el-table :data"ruleForm.tableDataShou" border style"width: 100%;"><el-table-column type"index" label"序号" wi…

数据预处理:随机裁剪放缩

随机裁剪放缩是一种数据增强技术&#xff0c;可以在训练神经网络时增加数据的多样性&#xff0c;提高模型的泛化能力。具体来说&#xff0c;随机裁剪放缩可以通过随机裁剪和缩放原始图片来生成多个不同的训练样本&#xff0c;从而增加数据集的大小和多样性。这种技术在图像分类…

Flink-时间流与水印

时间流与水印 一、背景二、时间语义1.事件时间&#xff08;event time&#xff09;2.读取时间&#xff08;ingestion time&#xff09;3.处理时间&#xff08;processing time&#xff09; 三、水印-Watermarks1.延迟和正确性2.延迟事件3.顺序流4.无序流5.并行流 四、Windows1.…

Redis对象系统

前言 在Redis中有许多数据结构&#xff0c;比如&#xff1a;简单动态字符串(SDS)&#xff0c;双端链表&#xff0c;字典&#xff0c;压缩列表&#xff0c;整数集合等。 Redis并没有直接使用这些数据结构来实现键值对数据库&#xff0c;而是基于这些数据结构创建了一个对象系统。…

脚本格式问题记录

服务器上的一些脚本迁移到其他服务上发生的小问题 问题&#xff1a;执行一个在win10系统编写好的shell脚本&#xff0c;放到Linux上执行报错如下&#xff1a; bash: ./xxx.sh: /bin/bash^M: bad interpreter: No such file or directory 原因&#xff1a;window系统写的脚本&a…

【Spring Boot 源码学习】BootstrapRegistryInitializer 详解

Spring Boot 源码学习系列 BootstrapRegistryInitializer 详解 引言往期内容主要内容1. 初识 BootstrapRegistryInitializer2. 加载 BootstrapRegistryInitializer3. BootstrapRegistryInitializer 的初始化 总结 引言 书接前文《初识 SpringApplication》&#xff0c;我们从 …

A*算法学习

系列文章目录 前言 在总结 2023华为软件精英挑战赛——全赛段思路分享与总结 - 知乎 (zhihu.com)时&#xff0c;发现自己还有很多技术细节没搞懂&#xff0c;这里看静态全局路径规划最常见的A*算法&#xff0c;这个博主讲得很好&#xff1a; A-Star&#xff08;A*&#xff0…

第十五届蓝桥杯(Web 应用开发)模拟赛 2 期-大学组(详细分析解答)

目录 1.相不相等 1.1 题目要求 1.2 题目分析 1.3 源代码 2.三行情书 2.1 题目要求 2.2 题目分析 2.3 源代码 3.电影院在线订票 3.1 题目要求 3.2 题目分析 3.3 源代码 4.老虎坤&#xff08;不然违规发不出来&#xff09; 4.1 题目要求 4.2 题目分析 4.3 源代码 …

mac 聚焦搜索不显示

我是连搜索框都不显示&#xff0c;不是搜索结果显示异常 点右上角的搜索按钮都毫无反应 我检查过快捷键之类的设置&#xff0c;都正常&#xff0c;最后是通过删除文件解决的 cd ~/Library/Preferences/ rm com.apple.Spotlight.plist 重启 mac 参考 Spotlight Search Not W…