项目场景:
在进行在线使用Spring Security
做为权限框架的办公系统的个人项目开发中,控制台输出的错误信息为无法写入JSON的错误,遇到了这个比较让人摸不着头脑的问题,我想应该不局限于当前项目场景,将目前遇到这种错误的解决方法进行记录,如果以后再遇到相同的错误,有不同解决方法时再回来记录。
问题描述
要实现的功能是获取管理员列表,向后端传递的参数和数据库中想要查询的内容也可以正常的获取到,但是在将查询到的数据返回到前端时就出现了报错
Swagger调试的内容如下:
从控制台的截图可以看到数据库中的数据正常返回以及前端传递的参数正常接收
控制台报错如下:
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: A granted authority textual representation is required; nested exception is com.fasterxml.jackson.databind.JsonMappingException: A granted authority textual representation is required (through reference chain: java.util.ArrayList[0]->net.csdn.server.pojo.Admin["authorities"])]
将问题进行翻译后可以知道内容为:
[org.springframework.http.converter.HttpMessageNotWritableException:无法写入 JSON:需要授予权限的文本表示; 嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException:需要授予权限的文本表示(通过引用链:java.util.ArrayList[0]->net.csdn.server.pojo.Admin[“authorities”]) ]
原因分析:
出现了这种问题,首先可以在控制台中看到是Admin
类中的某个字段需要授予权限,因此问题就在于Admin
类中的字段上,首先能够想到考虑以下几点( 项目中引入了lombok
, 同时Admin
类实现了UserDetails
接口 )
lombok
的@Data
注解没有加上,导致某些字段没有getter
以及setter
方法- 对于
Spring Security
中UserDetails
的接口字段有一些是不需要返回给前端的
对应的Admin
类代码如下:
package net.csdn.server.pojo; 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 io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; 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; import java.util.stream.Collectors; /** * <p> * * </p> * * @author zhangrongkang * @since 2022-01-23 */ @Data @EqualsAndHashCode(callSuper = false) @TableName("t_admin") @ApiModel(value="Admin对象", description="") public class Admin implements Serializable, UserDetails { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "id") @TableId(value = "id", type = IdType.AUTO) private Integer id; @ApiModelProperty(value = "姓名") private String name; @ApiModelProperty(value = "手机号码") private String phone; @ApiModelProperty(value = "住宅电话") private String telephone; @ApiModelProperty(value = "联系地址") private String address; @ApiModelProperty(value = "是否启用") private Boolean enabled; @ApiModelProperty(value = "用户名") private String username; @ApiModelProperty(value = "密码") private String password; @ApiModelProperty(value = "用户头像") private String userFace; @ApiModelProperty(value = "备注") private String remark; @ApiModelProperty(value = "角色") @TableField(exist = false) private List<Role> roles; /** * 通过角色名获取到对应的权限 * * @return 与角色名对应的权限集合 */ @Override public Collection<? extends GrantedAuthority> getAuthorities() { List<SimpleGrantedAuthority> authorities = roles .stream() .map(role -> new SimpleGrantedAuthority(role.getName())) .collect(Collectors.toList()); return authorities; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return enabled; } }
可以看到在Admin
类中是有@Data
注解的,因此排除第一种可能的情况。对于第二种情况来说,发现重写的getAuthorities
方法中返回的authorities
与控制台中的报错字段一致,因此可以将问题缩小至前端不需要将authorities
进行返回
解决方案:
在当前Admin
类中的getAuthorities
方法上添加@JsonIgnore
注解,将getAuthorities
方法返回的内容不出现在返回结果中
在添加该注解后,代码正常运行
总结:
无法将JSON
返回到前端有很多原因,这里的解决方法是对UserDetails
的实现类中的方法添加注解,表示其返回到内容不需要返回到前端。对@JsonIgnore
注解的使用进行一个小的总结
- 作用:在
JSON
序列化时将Java Bean
中的⼀些属性忽略掉,序列化和反序列化都受影响 - 使⽤场景:⼀般标记在属性或者⽅法上,返回的
Json
数据即不包含该属性