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

MapStruct映射Spring Boot实体时所有字段被PasswordEncoder加密,仅需加密密码字段的问题求助

MapStruct映射Spring Boot实体时所有字段被PasswordEncoder加密,仅需加密密码字段的问题求助

你遇到的这个问题我之前也踩过坑!核心原因是MapStruct的自动类型转换匹配逻辑:你的Mapper里定义了一个default String encodePassword(String, PasswordEncoder)方法,它的输入和输出都是String类型,MapStruct会把这个方法当作全局默认的String→String转换器,自动应用到所有需要将String源字段映射到String目标字段的场景——也就是你的nombre、apellido、email、rol、contrasena所有String类型字段,所以才会出现全字段被加密的离谱情况。

下面给你两种靠谱的解决方案,都能完美解决这个问题:

方案一:用@Named注解标记加密方法(推荐)

通过@Named给加密方法打上专属标记,然后在密码字段的映射规则里明确指定使用这个方法,这样MapStruct就不会乱把它应用到其他字段了:

import org.mapstruct.Named;
import org.mapstruct.Mapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingConstants;

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface UsuarioRegisterMapper {

    @Mapping(target = "rol", constant = "User")
    @Mapping(target = "id", ignore = true)
    // 明确指定contrasena字段使用名为encodePassword的转换方法
    @Mapping(target = "contrasena", source = "contrasena", qualifiedByName = "encodePassword")
    Usuario toEntity(RegisterRequest request, @Context PasswordEncoder passwordEncoder);

    // 用@Named标记这个方法是专门用来加密密码的
    @Named("encodePassword")
    default String encodePassword(String rawPassword, @Context PasswordEncoder passwordEncoder) {
        return passwordEncoder.encode(rawPassword);
    }
}

方案二:用@AfterMapping单独处理密码加密

先完成所有普通字段的基础映射,再通过@AfterMapping钩子单独给密码字段加密,逻辑更清晰:

import org.mapstruct.AfterMapping;
import org.mapstruct.Mapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingConstants;
import org.mapstruct.MappingTarget;

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface UsuarioRegisterMapper {

    @Mapping(target = "rol", constant = "User")
    @Mapping(target = "id", ignore = true)
    @Mapping(target = "contrasena", ignore = true) // 先忽略密码字段的映射
    Usuario toEntity(RegisterRequest request);

    // 基础映射完成后,单独给密码字段加密赋值
    @AfterMapping
    default void encodePassword(@MappingTarget Usuario usuario, RegisterRequest request, @Context PasswordEncoder passwordEncoder) {
        usuario.setContrasena(passwordEncoder.encode(request.contrasena()));
    }
}

效果验证

修改后,MapStruct生成的实现类只会对contrasena字段执行加密逻辑,其他字段会直接映射。比如生成的UsuarioRegisterMapperImpl会变成这样:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2025-07-14T21:19:15-0600",
    comments = "version: 1.5.5.Final, compiler: javac, environment: Java 23.0.2 (Oracle Corporation)"
)
@Component
public class UsuarioRegisterMapperImpl implements UsuarioRegisterMapper {

    @Override
    public Usuario toEntity(RegisterRequest request, PasswordEncoder passwordEncoder) {
        if (request == null) {
            return null;
        }

        Usuario usuario = new Usuario();

        usuario.setRol("User");
        usuario.setNombre(request.nombre());
        usuario.setApellido(request.apellido());
        usuario.setEmail(request.email());
        usuario.setContrasena(encodePassword(request.contrasena(), passwordEncoder));

        return usuario;
    }

    // 对应的encodePassword方法实现...
}

这样一来,你的nombre、apellido这些字段就会直接用原始值,不会被加密成超长的哈希串,自然也不会触发PostgreSQL的长度限制错误了。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 11:18:04