问题描述:
在基于Spring MVC的RESTful接口,当接口中请求参数Bean或者返回实体类的字段被@JsonProperty(access = Access.WRITE_ONLY) 约束时,通过postman调用rest接口,可以得到该字段可以值,也就是get/set是没问题的。
当通过feign接口调用时,该字段会被序列化为字节码传到所在服务的机器上,当反序列化该字段时,得到的字段值为null
原因:
被Access.WRITE_ONLY约束的字段值不会被序列化进去,所以对方获得的值为null。而postman直调服务器时,是将值直接序列化为字节码,所以可以获取到值。
解决办法:
摒弃该约束字段的Bean,新建一个Bean进行访问,调feign接口。
具体问题案例与解决:(feign调用无法获取到用户角色roles,本身controller可以获取到)
user模块的user实体类与dto类:
package com.byx.scaffold.user.entity;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import com.byx.scaffold.common.entity.jpa.BaseEntity;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonProperty.Access;
import lombok.Data;
import lombok.ToString;
import lombok.EqualsAndHashCode;
/** 用户 */
@ToString(exclude = "password")
@Data
@EqualsAndHashCode(callSuper=false)
@Entity
@Table(name = "app_user")
public class User extends BaseEntity {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@Column(length = 50, unique = true, nullable = false)
private String username;
@Column(length = 50)
private String name;
/** 头像 **/
private String avatar;
/** 手机号码 */
@Column(unique = true)
private String phone;
/** 邮箱 */
private String email;
/** 用户所属的组织类型(公司、政府部门) */
private String orgType;
/** 组织名称(可能是公司,也可能是政府部门) */
private String orgName;
@JsonProperty(access = Access.WRITE_ONLY )
@Column(nullable = false)
private String password;
/** 账号禁用 */
private boolean disabled;
@JsonProperty(access = Access.WRITE_ONLY )
@ManyToMany
@JoinTable(name = "app_user_role", joinColumns = @JoinColumn(name= "user_id"), inverseJoinColumns = @JoinColumn(name= "role_id"))
private List<Role> roles;
public void replaceRoles(List<Role> roles) {
this.roles.clear();
if (roles != null) {
this.roles.addAll(roles);
}
}
public User() {}
public User(Integer id, String username, String name) {
this.id = id;
this.username = username;
this.name = name;
}
}
package com.byx.scaffold.user.dto;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.byx.scaffold.user.entity.Role;
import com.byx.scaffold.user.entity.User;
import lombok.Data;
import javax.persistence.Column;
@Data
public class UserDTO {
private Integer id;
private String username;
private String name;
private String avatar;
private String phone;
private String email;
private boolean disabled;
private List<Role> roles;
/** 用户所属的组织类型(公司、政府部门) */
private String orgType;
/** 组织名称(可能是公司,也可能是政府部门) */
private String orgName;
public UserDTO(User user) {
this.id = user.getId();
this.username = user.getUsername();
this.name = user.getName();
this.avatar = user.getAvatar();
this.phone = user.getPhone();
this.email = user.getEmail();
this.disabled = user.isDisabled();
this.orgType = user.getOrgType();
this.orgName = user.getOrgName();
Stream<Role> stream = user.getRoles().stream();
this.roles = stream.map(r -> {
Role role = new Role();
role.setId(r.getId());
role.setName(r.getName());
return role;
}).collect(Collectors.toList());
}
public UserDTO(String username, String name) {
this.username = username;
this.name = name;
}
}
controller类
/**
* 根据用户名查询用户详细信息
* @param username
* @return
*/
@GetMapping("/user-by-username")
public UserDTO getUserInfo(String username) {
return userService.selectUserInfo(username);
}
serviceimpl类
@Override
public UserDTO selectUserInfo(String username) {
Optional<User> optional = userRepo.findByUsername(username);
return optional.map(UserDTO::new).orElse(null);
}
common公共类dto实体:
package com.byx.scaffold.common.dto;
import com.byx.scaffold.common.entity.user.Role;
import lombok.Data;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Data
public class UserDTO {
private Integer id;
private String username;
private String name;
private String avatar;
private String phone;
private String email;
private boolean disabled;
private List<Role> roles;
/** 用户所属的组织类型(公司、政府部门) */
private String orgType;
/** 组织名称(可能是公司,也可能是政府部门) */
private String orgName;
}
feign接口:
package com.byx.scaffold.context.feign;
import com.byx.scaffold.common.dto.MessageDTO;
import com.byx.scaffold.common.dto.UserDTO;
import com.byx.scaffold.common.response.BaseResponse;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@FeignClient(value = "user")
public interface IUserFeign {
/**
* 根据用户名获取用户详细信息
*
* @return
*/
@GetMapping("user/user/user-by-username")
UserDTO getUserInfo(String username);
}