You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot API多类型用户JWT登录与跨表数据入库问题

问题描述

我在SpringBoot API中已实现带有JWT令牌逻辑的user表,该表包含username、password、email和status字段(用于标记用户是否活跃,而非直接删除数据)。目前需要扩展三类用户:

  • Admin:新增所属公司字段
  • Veterinary:新增更多专属数据
  • Client:新增不同专属数据

这三类用户表均继承自user表,但我不清楚如何实现Client这类用户注册时,既完成user表的数据填充、JWT令牌生成,又将Client的专属数据存入对应的cliente表中。


现有代码

认证服务代码

package com.ApiRestfulBackendVet.ApiRestfulBackendVet.Auth;

import com.ApiRestfulBackendVet.ApiRestfulBackendVet.user.role;
import com.ApiRestfulBackendVet.ApiRestfulBackendVet.user.user;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import com.ApiRestfulBackendVet.ApiRestfulBackendVet.Jwt.jwtService;
import com.ApiRestfulBackendVet.ApiRestfulBackendVet.user.userRepository;
import com.ApiRestfulBackendVet.ApiRestfulBackendVet.Config.ApplicationConfig;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.ApiRestfulBackendVet.ApiRestfulBackendVet.repositories.IAdminRepository;
import javax.management.relation.Role;

@Service
@RequiredArgsConstructor
public class authService {

    private final userRepository userRepository;
    private final jwtService jwtService;
    private final PasswordEncoder passwordEncoder;
    private final AuthenticationManager authenticationManager;
    private final IAdminRepository adminRepository;

    public authResponse login (loginRequest request) {
        authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(request.getUsername(), request.getContraseña()));
        UserDetails userDetails = userRepository.findByUsername(request.getUsername()).orElseThrow();
        String token = jwtService.getToken(userDetails);
        return authResponse.builder()
                .token(token)
                .build();
    }
    //Register admindios
    public authResponse register (registerRequest request) {
        user user1 = user.builder()
                .email(request.getEmail())
                .username(request.getUsername())
                .contrasena(passwordEncoder.encode( request.getContraseña()))
                .role(role.ADMINDIOS)
                .build();

        userRepository.save(user1);

        return authResponse.builder()
                .token(jwtService.getToken(user1))
                .build();
    }

}

User实体类代码

package com.ApiRestfulBackendVet.ApiRestfulBackendVet.user;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "user")
public class user implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "email")
    private String email;

    @Column(name = "contraseña")
    private String contrasena;

    @Column(name = "username")
    private String username;

    @Column(name = "estatus")
    private String estatus;

    @Enumerated(EnumType.STRING)
    role role;

}

Client实体类代码

package com.ApiRestfulBackendVet.ApiRestfulBackendVet.models;

import com.ApiRestfulBackendVet.ApiRestfulBackendVet.user.user;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "cliente")
public class clientModel extends user {

    @Column(name = "nombre_usuario")
    private String nombreUsuario;
    @Column(name = "numero_contacto")
    private String numeroContacto;
    @Column(name = "foto_perfil")
    private String fotoPerfil;
    @Column(name = "id_sucursal")
    private int idSucursal;
}

User仓库代码

package com.ApiRestfulBackendVet.ApiRestfulBackendVet.user;

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface userRepository extends JpaRepository<user, Integer> {
    Optional<user> findByUsername(String username);
}

注册请求类代码

package com.ApiRestfulBackendVet.ApiRestfulBackendVet.Auth;

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

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class registerRequest {
    String email;
    String username;
    String contraseña;
    String estatus;
}

解决方案

1. 扩展注册请求类,添加Client专属字段

创建包含Client专属数据的注册请求类:

package com.ApiRestfulBackendVet.ApiRestfulBackendVet.Auth;

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

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ClientRegisterRequest {
    // User表基础字段
    String email;
    String username;
    String contraseña;
    String estatus;
    // Client专属字段
    String nombreUsuario;
    String numeroContacto;
    String fotoPerfil;
    int idSucursal;
}

2. 创建Client仓库接口

用于操作cliente表:

package com.ApiRestfulBackendVet.ApiRestfulBackendVet.repositories;

import com.ApiRestfulBackendVet.ApiRestfulBackendVet.models.clientModel;
import org.springframework.data.jpa.repository.JpaRepository;

public interface IClientRepository extends JpaRepository<clientModel, Integer> {
}

3. 修改认证服务,实现Client注册逻辑

在authService中注入IClientRepository,并添加Client注册方法:

@Service
@RequiredArgsConstructor
public class authService {

    // 原有依赖注入
    private final userRepository userRepository;
    private final jwtService jwtService;
    private final PasswordEncoder passwordEncoder;
    private final AuthenticationManager authenticationManager;
    private final IAdminRepository adminRepository;
    // 新增Client仓库注入
    private final IClientRepository clientRepository;

    // 原有login方法保持不变

    // 原有Admin注册方法保持不变

    // 新增Client注册方法
    public authResponse registerClient(ClientRegisterRequest request) {
        // 构建Client实例,同时填充User表字段
        clientModel client = clientModel.builder()
                .email(request.getEmail())
                .username(request.getUsername())
                .contrasena(passwordEncoder.encode(request.getContraseña()))
                .estatus(request.getEstatus())
                .role(role.CLIENT) // 确保role枚举中存在CLIENT类型
                .nombreUsuario(request.getNombreUsuario())
                .numeroContacto(request.getNumeroContacto())
                .fotoPerfil(request.getFotoPerfil())
                .idSucursal(request.getIdSucursal())
                .build();

        // 保存Client实例:由于JOINED继承策略,JPA会自动将父类数据写入user表,子类数据写入cliente表
        clientRepository.save(client);

        // 生成并返回JWT令牌
        return authResponse.builder()
                .token(jwtService.getToken(client))
                .build();
    }
}

4. 关键说明

  • 你的user实体已使用@Inheritance(strategy = InheritanceType.JOINED),保存子类(如clientModel)时,JPA会自动拆分数据到父类表和子类表,无需手动操作两张表。
  • 登录逻辑无需修改:认证基于user表的username,生成JWT后,若需获取Client专属数据,可通过userRepository查询后强转为clientModel,或通过IClientRepository根据ID查询。
  • 确保role枚举中添加CLIENT类型,避免注册时抛出异常。

内容的提问来源于stack exchange,提问作者user24716939

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 10:07:05