@JsonView的使用场景

在某一些请求返回的JSON中,我们并不希望返回某些字段。而在另一些请求中需要返回某些字段。 例如有如下用户对象:

public class User implements Serializable {
	private Integer id;
	private String username;
	private String password;
}

在查询列表请求中,不返回password字段。在获取用户详情中,返回password字段。这时候我们就可以使用 @JsonView注解了。

使用@JsonView的步骤

1.使用接口来声明多个视图

2.在值对象的get方法上指定视图

3.在Controller的方法上指定视图

1、2两步的代码如下:

public class User implements Serializable {
	private Integer id;
	private String username;
	private String password;
	
	/**
	 * 1.使用接口声明多个视图
	 */
	public interface UserSimpleView {};
	public interface UserDetailView extends UserSimpleView {};
	
	/**
	 * 2.在值对象的get方法上指定视图
	 */
	@JsonView(UserSimpleView.class)
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	@JsonView(UserSimpleView.class)
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	@JsonView(UserDetailView.class)
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
}

3步的代码如下

@RestController
public class UserController {
	
	@Autowired
	private UserService userService;

	/**
	 * 3.在Controller方法上指定视图
	 */
	@RequestMapping(value = "/getuser", method = RequestMethod.GET)
	@JsonView(User.UserSimpleView.class)
	public List<User> queryUser(@RequestParam(value = "page", defaultValue = "0") Integer page,
            @RequestParam(value = "size", defaultValue = "10") Integer size) {
		PageRequest request = PageRequest.of(page, size, new Sort(Sort.Direction.DESC, "id"));
		Page<User> userPage = userService.findAllUser(request);
		return userPage.getContent();
	}
	
	@RequestMapping(value = "/getuser/{id}", method = RequestMethod.GET)
	@JsonView(User.UserDetailView.class)
	public User getUserInfo(@PathVariable Integer id) {
		User user = userService.getUserById(id);
		return user;
	}
}

省略了一些service、和dao的代码。

@JsonView无法正确应用到自己封装的ResultVo

实际开发过程中,我们需要自己封装返回的数据。通常我们会定义UserDtoResultVo。如下:

public class UserDto implements Serializable {
	private Integer id;
	private String username;
	private String password;
	
	public interface UserDtoSimpleView {};
	public interface UserDtoDetailView extends UserDtoSimpleView {};
	
	@JsonView(UserDtoSimpleView.class)
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	@JsonView(UserDtoSimpleView.class)
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	@JsonView(UserDtoDetailView.class)
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	
}

public class ResultVo<T> implements Serializable {
	private Integer code;
	private String msg;
	private T data;
	/*省略getter、setter*/
}

此时我们在Ctroller中使用@JsonView,如下代码:

@RestController
public class UserController {
	
	@Autowired
	private UserService userService;
	
	@RequestMapping(value = "/user", method = RequestMethod.GET)
	@JsonView(UserDto.UserDtoSimpleView.class)
	public ResultVo<Object> query(@RequestParam(value = "page", defaultValue = "0") Integer page,
            @RequestParam(value = "size", defaultValue = "10") Integer size) {
		PageRequest request = PageRequest.of(page, size, new Sort(Sort.Direction.DESC, "id"));
		ResultVo<Object> resultVo = null;
		try {
			Page<UserDto> userPage = userService.findAllUserDto(request);
			resultVo = ResultVoUtil.success(userPage);
		} catch (Exception e) {
			e.printStackTrace();
			resultVo = ResultVoUtil.error();
		}
        return resultVo;
    }
	
	@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
	@JsonView(UserDto.UserDtoDetailView.class)
	public ResultVo<Object> getInfo(@PathVariable Integer id) {
		ResultVo<Object> resultVo = null;
		try {
			UserDto userDto = userService.getUserDtoById(id);
			resultVo = ResultVoUtil.success(userDto);
		} catch (Exception e) {
			e.printStackTrace();
			resultVo = ResultVoUtil.error();
		}
        return resultVo;
	}
}

这个使用并不能返回我们预期的结果,而是返回一个空json集合。实际上,当我们在封装了dto之后,

我们就已经默认封装了需要返回的数据,如果没有特别的需求,没有必要一定要定义特殊的返回。

如果真的想要排除某些数据,网上有人使用JsonConfig对象去配置。示例代码如下:

JsonConfig jc=new JsonConfig();
// 使用setExcludes方法过滤,例如我不想要对象中的roleinfo和departmentInfo:
jc.setExcludes(new String[]{"password","salt","roles","roleSet","shops","permissionsSet"});

这种方式尝试了一下,由于时代的关系…jar包不好管理。所有没能够正常实现。这里使用了com.alibaba.fastjson。引入版本:

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastJson</artifactId>
<version>1.2.7</version>
</dependency>

controller中的代码为:

@RestController
public class UserController {
	
	@Autowired
	private UserService userService;
	
	@RequestMapping(value = "/user", method = RequestMethod.GET)
	public ResultVo<Object> query(@RequestParam(value = "page", defaultValue = "0") Integer page,
            @RequestParam(value = "size", defaultValue = "10") Integer size) {
		PageRequest request = PageRequest.of(page, size, new Sort(Sort.Direction.DESC, "id"));
		ResultVo<Object> resultVo = null;
		/**
		 * 1.构建排除集合
		 * 2.创建属性过滤对象
		 * 3.添加过滤集合到属性过滤对象
		 */
		List<String> excludes = new ArrayList<String>();
		excludes.add("password");
        SimplePropertyPreFilter filter = new SimplePropertyPreFilter();
        filter.getExcludes().addAll(excludes);
		try {
			Page<UserDto> userPage = userService.findAllUserDto(request);
			/**
			 * 1.获取排除字段后的新的json集合
			 * 2.生成新的排除字段值后的集合对象
			 * 3.构建返回对象
			 */
			String jsonStr = JSON.toJSONString(userPage.getContent(), filter);
			List<UserDto> list = JSONObject.parseArray(jsonStr, UserDto.class);
			PageImpl<UserDto> pageImpl = new PageImpl<UserDto>(
					list, request, userPage.getTotalElements());
			resultVo = ResultVoUtil.success(pageImpl);
		} catch (Exception e) {
			e.printStackTrace();
			resultVo = ResultVoUtil.error();
		}
        return resultVo;
    }
	
	@RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
	public ResultVo<Object> getInfo(@PathVariable Integer id) {
		ResultVo<Object> resultVo = null;
		try {
			UserDto userDto = userService.getUserDtoById(id);
			resultVo = ResultVoUtil.success(userDto);
		} catch (Exception e) {
			e.printStackTrace();
			resultVo = ResultVoUtil.error();
		}
        return resultVo;
	}

}

按照此方法能够正常的实现排除了密码部分的返回值,但是这里有个遗留问题,就是尽管排除了,但是在二次 构建List<UserDto>时,引入了password属性,所以返回值中,所有password都是null

当然这个问题可以解决,但是个人不建议继续处理。

原文链接: https://marshucheng1.github.io/2017/03/11/@JsonView%E4%BD%BF%E7%94%A8/