[fasterxml.jackson] 필드 역직렬화 문제 Access.WRITE_ONLY

문제 설명:

Spring MVC 기반의 RESTful 인터페이스에서 요청 파라미터 Bean 또는 인터페이스에서 반환된 엔티티 클래스의 필드가 @JsonProperty(access = Access.WRITE_ONLY)에 의해 제약을 받는 경우 나머지를 호출하여 해당 필드의 값을 얻을 수 있다. Postman을 통한 인터페이스, 즉 get/set은 문제가 되지 않습니다.

feign 인터페이스를 통해 호출하면 필드가 바이트코드로 직렬화되어 서비스가 있는 머신으로 전송되며, 필드가 역직렬화되면 획득한 필드 값은 null이 됩니다.

이유:

Access.WRITE_ONLY로 제한되는 필드 값은 직렬화되지 않으므로 상대방이 얻은 값은 null입니다. Postman이 서버를 직접 조정할 때 값을 직접 바이트코드로 직렬화하므로 값을 얻을 수 있습니다.

해결책:

제약 조건 필드의 Bean을 버리고 액세스를 위한 새 Bean을 생성하고 feign 인터페이스를 호출합니다. 

특정 문제 사례 및 솔루션: (feign 호출은 사용자 역할 역할을 얻을 수 없지만 컨트롤러 자체는 이를 얻을 수 있습니다.)

사용자 모듈의 사용자 엔터티 클래스 및 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);
    }

공통 공용 클래스 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;

}

가짜 인터페이스:

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);
}

おすすめ

転載: blog.csdn.net/gp_911014/article/details/130942987