Springboot+vue+策略+工厂模式+装饰模式实现简单的登录界面

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

有这样一个需求,我们需要设计一个用户认证类,使用策略模式实现多种认证算法(例如用户名密码认证、短信验证码认证、第三方登录认证),并可以选择使用不同的认证算法来进行用户认证。

我们使用springboot+vue来完成登录功能和前端页面的展示,并使用策略加工厂模式来实现对不同认证算法的实现。后续考虑到密码的安全性问题,我们会使用装饰模式在不修改源代码的情况下,新增一个密码md5+salt盐并且反转的加密方法,并将当前登陆的用打印到txt文档中。

(需要源代码的可以私信联系我喔)

提示:以下是本篇文章正文内容,下面案例可供参考

一、后端代码

类图和项目结构

在这里插入图片描述
在这里插入图片描述

策略加工厂模式代码

策略接口

package com.demo.strategyService;

import com.demo.common.LoginServiceEnum;
import com.demo.domain.RequestLogin;

public interface LoginService {
    LoginServiceEnum getStrategy();
    Boolean doLogin(RequestLogin user);
}

实现

package com.demo.strategyService;

import com.demo.common.LoginServiceEnum;
import com.demo.domain.RequestLogin;
import org.springframework.stereotype.Component;

@Component
public class EmailLoginStrategy implements LoginService{


    @Override
    public LoginServiceEnum getStrategy() {
        return LoginServiceEnum.LOGIN_EMAIL;
    }

    @Override
    public Boolean doLogin(RequestLogin user) {
        System.out.println("这是短信登录");
        return true;

    }
}

package com.demo.strategyService;

import com.demo.common.LoginServiceEnum;
import com.demo.domain.DemoUser;
import com.demo.domain.RequestLogin;
import com.demo.mapper.DemoUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
@Component
@Slf4j
public class NormalLoginStrategy implements LoginService{
  @Resource
  private DemoUserMapper demoUserMapper;

    @Override
    public LoginServiceEnum getStrategy() {
        return LoginServiceEnum.LOGIN_NOR;
    }

    @Override

    public Boolean doLogin(RequestLogin user) {
        DemoUser userByName = demoUserMapper.getUserByName(user.getUsername());
        if (user.getUsername() != "" && user.getUsername().equals(userByName.getUsername())){
               if (userByName.getPassword() != null && user.getPassword().equals(userByName.getPassword())){
                   log.info("这是普通的登录方法,登录成功");
                   return true;
               }
               return false;
        }

       return false;
    }
}

package com.demo.strategyService;

import com.demo.common.LoginServiceEnum;
import com.demo.domain.RequestLogin;
import org.springframework.stereotype.Component;

@Component
public class WeChatLoginStrategy implements LoginService{


    @Override
    public LoginServiceEnum getStrategy() {
        return LoginServiceEnum.LOGIN_WECHAT;
    }

    @Override
    public Boolean doLogin(RequestLogin user) {
        System.out.println("这是WEChAT登录方法");
        return true;

    }
}

工厂类

package com.demo.factory;

import com.demo.common.LoginServiceEnum;
import com.demo.strategyService.LoginService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
public class LoginTypeFactory implements InitializingBean {
    @Resource
    List<LoginService> loginServiceList;

    private Map<LoginServiceEnum,LoginService> handlerMap = new HashMap<>();

    public LoginService getStrategy(int subjectType){
        // ResultCodeEnum resultCodeEnum = SubjectInfoTypeEnum.getByCode(subjectType);
        LoginServiceEnum resultCodeEnum = LoginServiceEnum.getByCode(subjectType);
        System.out.println(resultCodeEnum);
        return handlerMap.get(resultCodeEnum);
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        //在Spring容器初始化这个类(LoginTypeFactory)的时候,
        // 会自动查找Spring容器中所有的LoginFactory类型的Bean,并将这些Bean注入到loginFactories这个列表中。
        // 这样,在SubjectTypeHandlerFactory类中就可以直接使用这个列表,
        // 而不需要手动去查找和获取这些SubjectTypeHandler类型的Bean。
        for (LoginService loginService : loginServiceList){
            handlerMap.put(loginService.getStrategy(),loginService);
        }
    }


}

枚举类

package com.demo.common;

import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.Objects;

@Getter
@AllArgsConstructor
public enum LoginServiceEnum {
    LOGIN_NOR(1, "普通登录"),

    LOGIN_EMAIL(2, "短信登录"),

    LOGIN_WECHAT(3,"微信登录");



    private Integer code;

    private String desc;


    LoginServiceEnum(int code, String desc){
        this.code = code;
        this.desc = desc;

    }

    public static LoginServiceEnum getByCode(int codeVal){
        for(LoginServiceEnum resultCodeEnum : LoginServiceEnum.values()){
            if(resultCodeEnum.code == codeVal){
                return resultCodeEnum;
            }
        }
        return null;
    }
}

返回结果集

package com.demo.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MYResult<T> {
    //状态码
    private Integer code ;
    //消息提示
    private String message ;
    //数据  List , Map, String , Book , Student
    private T data ;
    //操作成功,没有数据返回
    public static<T> MYResult<T> success(){
        return new MYResult<>(20000, "操作成功" ,null);
    }

    //操作成功,返回数据
    public static<T> MYResult<T> success(T data){
        return new MYResult<>(20000, "操作成功" ,data);
    }

    public static<T> MYResult<T> success(String message){
        return new MYResult<>(20000, message ,null);
    }

    public static<T> MYResult<T> success(String message, T data){
        return new MYResult<>(20000, message ,data);
    }

    public static<T> MYResult<T> success(Integer code , String message, T data){
        return new MYResult<>(code, message ,data);
    }
    public static<T> MYResult<T> fail(){
        return new MYResult<>(60204, "操作失败" ,null);
    }

    public static<T> MYResult<T> fail(String message){
        return new MYResult<>(60204, message ,null);
    }

    public static<T> MYResult<T> fail(Integer code , String message){
        return new MYResult<>(code , message , null);
    }

    public static<T> MYResult<T> fail(Integer code , String message, T data){
        return new MYResult<>(code , message , data);
    }

}

实体类

package com.demo.domain;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.io.Serializable;

/**
 * 
 * @TableName demo_user
 */
@TableName(value ="demo_user")
public class DemoUser implements Serializable {
    /**
     * 
     */
    @TableId(type = IdType.AUTO)
    private Integer id;

    /**
     * 
     */
    private String username;

    /**
     * 
     */
    private String password;

    @TableField(exist = false)
    private static final long serialVersionUID = 1L;

    /**
     * 
     */
    public Integer getId() {
        return id;
    }

    /**
     * 
     */
    public void setId(Integer id) {
        this.id = id;
    }

    /**
     * 
     */
    public String getUsername() {
        return username;
    }

    /**
     * 
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * 
     */
    public String getPassword() {
        return password;
    }

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

    @Override
    public boolean equals(Object that) {
        if (this == that) {
            return true;
        }
        if (that == null) {
            return false;
        }
        if (getClass() != that.getClass()) {
            return false;
        }
        DemoUser other = (DemoUser) that;
        return (this.getId() == null ? other.getId() == null : this.getId().equals(other.getId()))
            && (this.getUsername() == null ? other.getUsername() == null : this.getUsername().equals(other.getUsername()))
            && (this.getPassword() == null ? other.getPassword() == null : this.getPassword().equals(other.getPassword()));
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
        result = prime * result + ((getUsername() == null) ? 0 : getUsername().hashCode());
        result = prime * result + ((getPassword() == null) ? 0 : getPassword().hashCode());
        return result;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append(" [");
        sb.append("Hash = ").append(hashCode());
        sb.append(", id=").append(id);
        sb.append(", username=").append(username);
        sb.append(", password=").append(password);
        sb.append(", serialVersionUID=").append(serialVersionUID);
        sb.append("]");
        return sb.toString();
    }
}
package com.demo.domain;

import lombok.Data;

@Data
public class RequestLogin {
    private String username;
    private String password;
    private Integer type;
}

mapper层代码及其xml

package com.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.demo.domain.DemoUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;


/**
* @author 18512
* @description 针对表【demo_user】的数据库操作Mapper
* @createDate 2024-04-10 20:22:03
* @Entity com.status.demo.domain.DemoUser
*/
@Mapper
public interface DemoUserMapper extends BaseMapper<DemoUser> {
    DemoUser getUserByName(String Name);

    Integer regsiterUser(@Param("username") String username, @Param("password") String password);
}





<?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.demo.mapper.DemoUserMapper">

    <resultMap id="BaseResultMap" type="com.demo.domain.DemoUser">
            <id property="id" column="id" jdbcType="INTEGER"/>
            <result property="username" column="username" jdbcType="VARCHAR"/>
            <result property="password" column="password" jdbcType="VARCHAR"/>
    </resultMap>

    <sql id="Base_Column_List">
        id,username,password
    </sql>
    <insert id="regsiterUser" >
        insert into demo_user (username, password)
        values (#{username}, #{password});
    </insert>
    <select id="getUserByName" resultType="com.demo.domain.DemoUser">
        select *
        from demo_user;
    </select>
</mapper>

service层代码及其实现

package com.demo.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.demo.domain.DemoUser;


/**
* @author 18512
* @description 针对表【demo_user】的数据库操作Service
* @createDate 2024-04-10 20:22:03
*/
public interface DemoUserService extends IService<DemoUser> {

    Integer registeUser(String username, String password);
}

package com.demo.service.impl;


import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.mapper.DemoUserMapper;
import com.demo.service.DemoUserService;

import org.springframework.stereotype.Service;
import com.demo.domain.DemoUser;
/**
* @author 18512
* @description 针对表【demo_user】的数据库操作Service实现
* @createDate 2024-04-10 20:22:03
*/
@Service
public class DemoUserServiceImpl extends ServiceImpl<DemoUserMapper, DemoUser>
    implements DemoUserService {

    @Override
    public Integer registeUser(String username, String password) {
        return this.baseMapper.regsiterUser(username,password);
    }
}





yml文件及其pom.xml文件

server:
  port: 9093
spring:
  application:
    name: MyDemo01
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/strategydemo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
      username: root
      password: 1234
mybatis-plus:
  configuration:
    #在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    banner: false
  mapper-locations: classpath:mapper/*.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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>MyAuthRoleChain</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>StrategyDemo</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.26</version>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>19.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>19.0</version>
        </dependency>


    </dependencies>

</project>

二、前端代码

1。前端项目结构

在这里插入图片描述

登录页面及其HomeCompent’页面

<template>
    <div>
      <h2>Login</h2>
      <form @submit.prevent="login">
        <div>
          <label for="username">Username:</label>
          <input v-model="credentials.username" type="text" id="username" required>
        </div>
        <div>
          <label for="password">Password:</label>
          <input v-model="credentials.password" type="password" id="password" required>
        </div>
        <div>
          <label for="type">Login Type:</label>
          <select v-model="credentials.type" id="type">
            <option value="1">普通登录</option>
            <option value="2">短信登录</option>
            <option value="3">微信登录</option>
          </select>
        </div>
        <button type="submit">Login</button>
      </form>
    </div>
  </template>
  
  <script>
  import axios from 'axios';
  
  export default {
    name: 'LoginComponent',
    data() {
      return {
        credentials: {
          username: '',
          password: '',
          type: '1', // 默认为 "普通登录"
        },
      };
    },
    methods: {
      async login() {
        try {
          const response = await axios.post('http://localhost:9093/login', this.credentials);
          if (response.data.code === 20000) {
            alert(`登录成功: ${response.data.message}`);
            // 使用 this.$router 访问路由实例,并跳转到 HomeComponent
            this.$router.push({ name: 'home' });
          } else {
            alert(`登录失败: ${response.data.message}`);
          }
        } catch (error) {
          console.error('登录错误:', error);
          alert('登录失败: 发生错误');
        }
      },
    },
  };
  </script>
  
<template>
    <div>
      <h1>Welcome to Home Page!</h1>
      <p>This is a simple home page component.</p>
    </div>
  </template>
  
  <script>
  export default {
    name: 'HomeComponent',
    // Options API 里可以定义 data, methods, computed 等选项
    data() {
      return {
        // 定义你的响应式数据
      };
    },
    methods: {
      // 定义方法
    },
    // 其他选项如 computed, watch, mounted 等生命周期钩子也可以在这里定义
  };
  </script>
  
  <style scoped>
  /* 你的CSS样式 */
  </style>
  

router路由

import { createRouter, createWebHistory } from 'vue-router'
import HomeComponent from '../components/HomeComponent.vue'

import LoginComponent from '../components/LoginComponent.vue'

const routes = [
 
  { path: '/', component: LoginComponent },
  { path: '/home', component: HomeComponent, name: 'home' }

  // 添加其他路由配置
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router


App.vue文件

在这里插入图片描述

效果

在这里插入图片描述

在这里插入图片描述

注册

在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot是一个用于创建独立的、基于Spring的生产级应用程序的框架,Vue是一个用于构建用户界面的JavaScript框架。 要实现简单的登录功能,可以按照以下步骤进行: 1. 创建一个Spring Boot项目,并添加所需的依赖项,包括Spring Security和Spring Data JPA。 2. 创建用户实体类,并使用Spring Data JPA创建相应的数据库表。 3. 创建一个用于处理用户注册和登录请求的控制器。例如,创建一个UserController类,在其中定义相应的请求映射方法,如/register和/login。 4. 在注册请求方法中,接收用户注册的信息,对密码进行加密,然后将用户信息保存到数据库中。 5. 在登录请求方法中,接收用户登录的信息,然后使用Spring Security对用户名和密码进行验证。 6. 创建一个用于处理前端页面的静态资源的目录,例如,在Spring Boot项目的resources/static目录下创建一个名为"static"的文件夹。 7. 在静态资源目录下创建一个用于前端页面的Vue应用程序,包括一个登录页面和相应的Vue组件。在Vue组件中,使用axios库发送HTTP请求到后端的登录接口,并根据返回的结果进行相应的处理,如跳转到首页或显示登录失败提示。 8. 在Spring Boot项目的配置文件中,配置允许跨域请求,以便前端Vue应用程序可以与后端进行通信。 9. 运行Spring Boot项目,并在浏览器中访问前端页面,测试登录功能是否正常工作。 通过以上步骤,您可以实现一个简单的登录功能,用户可以在前端页面进行注册和登录操作,后端使用Spring Boot处理请求,验证用户信息,并返回相应的结果给前端。这样,用户就能够通过用户名和密码进行登录。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值