为啥从 AOP 传递到具有其他参数的控制器的模型的所有属性都是空的

Posted

技术标签:

【中文标题】为啥从 AOP 传递到具有其他参数的控制器的模型的所有属性都是空的【英文标题】:Why all properties of a Model passed from AOP to controller with other arguments are null为什么从 AOP 传递到具有其他参数的控制器的模型的所有属性都是空的 【发布时间】:2020-12-28 14:37:01 【问题描述】:

AOP

@Around(
    "execution(* net.inter.warp.bridge.controller.*.*(.., net.inter.warp.bridge.model.User)) && " +
    "args(.., authenticatedUser)"
)
public Object withAuthenticatedUser(ProceedingJoinPoint joinPoint, User authenticatedUser) throws Throwable 
    System.out.println(joinPoint + " -> " + authenticatedUser);
    User user = null;
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (authentication != null)
        user = (User) userService.loadUserByUsername(authentication.getName());
    else
        throw new UnauthorizedException("err 1");
    if (user == null)
        throw new UnauthorizedException("err 2");
    return joinPoint.proceed(new Object[]user);

控制器(authenticatedUser 的所有属性都为空)

package net.inter.warp.bridge.controller;

@GetMapping("/boxes/id")
public ResponseEntity<Box> getBoxById(@PathVariable(value = "id") Long boxId, User authenticatedUser)
    throws NoDynamicTableFoundException, ResourceNotFoundException 

控制器(这是因为除了authenticatedUser之外没有更多参数了)

package net.inter.warp.bridge.controller;

@GetMapping("/boxes/id")
public ResponseEntity<Box> getBoxById(User authenticatedUser)
    throws NoDynamicTableFoundException, ResourceNotFoundException 

AOP 似乎讨厌其他参数... authenticatedUser 不为 null,authenticatedUser 的每个属性都为 null。

模型(我不确定这个问题是否与此有关)

@Entity
@Table(name="users")
@ToString
public class User extends AuthEntity implements UserDetails

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() 
        String[] userRoles = this.roles.stream().map((role) -> role.getName()).toArray(String[]::new);
        Collection<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList(userRoles);
        return authorities;
    

    @Override
    public String getUsername() 
        return this.email;
    

    @Override
    public boolean isAccountNonExpired() 
        return true;
    

    @Override
    public boolean isAccountNonLocked() 
        return true;
    

    @Override
    public boolean isCredentialsNonExpired() 
        return true;
    

    @Override
    public boolean isEnabled() 
        return true;
    

    @Column(nullable=false)
    @NotNull(message = "")
    private String name;

    @Column(nullable=false, unique=true)
    @Email
    //@NotBlank(message = "")
    private String email;

    @Column
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    @JsonIgnore
    private String password;


    @Column(length = 20, columnDefinition ="bigint")
    //@NotNull(message = "")
    private Long organization_id;

    @ManyToOne(optional=false)
    @JoinColumn(name = "organization_id",referencedColumnName="id", insertable=false, updatable=false)
    //@JsonIgnore
    private Organization organization;

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.MERGE)
    //@Fetch(org.hibernate.annotations.FetchMode.SELECT)
    @JoinTable(
            name="user_role",
            joinColumns=@JoinColumn(name="user_id"),
            inverseJoinColumns=@JoinColumn(name="role_id"))

    private List<Role> roles;

/*
    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.MERGE)
    //@Fetch(org.hibernate.annotations.FetchMode.SELECT)
    @Fetch(value = FetchMode.SUBSELECT)
    @JoinTable(
            name="hyperbridge_resource.user_workspace",
            joinColumns=@JoinColumn(name="user_id"),
            inverseJoinColumns=@JoinColumn(name="workspace_id"))

    private List<Workspace> workspaces;
*/

    @Column(length = 1, columnDefinition ="char")
    private String active;

    @Column(name = "reset_token")
    @JsonIgnore
    private String resetToken;

    @Column(name = "reset_token_time")
    @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Seoul")
    private LocalDateTime resetTokenTime;


    public String getName() 
        return name;
    

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

    public String getEmail() 
        return email;
    

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

    public String getPassword() 
        return password;
    

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

    public Long getOrganization_id() 
        return organization_id;
    

    public void setOrganization_id(Long organization_id) 
        this.organization_id = organization_id;
    

    public Organization getOrganization() 
        return organization;
    

    public void setOrganization(Organization organization) 
        this.organization = organization;
    

    public List<Role> getRoles() 
        return roles;
    

    public void setRoles(List<Role> roles) 
        this.roles = roles;
    

/*  public List<Workspace> getWorkspaces() 
        return workspaces;
    

    public void setWorkspaces(List<Workspace> workspaces) 
        this.workspaces = workspaces;
    */

    public String getActive() 
        return active;
    

    public void setActive(String active) 
        this.active = active;
    

    public String getResetToken() 
        return resetToken;
    

    public void setResetToken(String resetToken) 
        this.resetToken = resetToken;
    

    public LocalDateTime getResetTokenTime() 
        return resetTokenTime;
    

    public void setResetTokenTime(LocalDateTime resetTokenTime) 
        this.resetTokenTime = resetTokenTime;
    

【问题讨论】:

放弃你的方面,因为它破坏了正确调用该方法,并且 Spring Security 已经支持这种开箱即用的方法,你不需要 AOP。在你的方法参数上使用@AuthenticationPrincipal 我只能通过@AuthenticationPrincipal 获取用户名、密码、启用等,但我的用户对象中还有其他参数位于模型文件夹中。 如果您使用自己的 User 对象,您就不必使用 Spring Security User 对象。 我知道有很多方法但不希望控制器冗余,所以最终选择了这个-***.com/a/41327161/7344596 @GetMapping("/binders") public Page listBinder(@AuthenticationPrincipal AccessTokenUserInfo accessTokenUserInfo) /* 现在,不需要这个... User user = userRepository.findByEmail(accessTokenUserInfo. getUsername()).orElseThrow(() -> new UsernameNotFoundException("Email : " + accessTokenUserInfo.getUsername() + " not found"));*/ return binderService.findByPage(1, 2, accessTokenUserInfo.getId(), accessTokenUserInfo .getOrganization_id()); 【参考方案1】:

试试这个,doc:

@Around(
"execution(* net.inter.warp.bridge.controller.*.*(..) && " +
"args(authenticatedUser,..)"

【讨论】:

以上是关于为啥从 AOP 传递到具有其他参数的控制器的模型的所有属性都是空的的主要内容,如果未能解决你的问题,请参考以下文章

如何将模型传递给具有其他参数的动作

将模型和额外参数从视图传递到 MVC 中的操作

为啥从 jquery 传递给控制器​​方法的参数即使不是 null 也是 null?

如何将模型值从视图传递到控制器?

将值从模型传递到 CI 中的视图

iOS:如何使用 MVVM 将模型从视图模型传递到视图模型?