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
相关产品推荐
相关产品推荐

