例如一个获取用户信息的功能,但是可能不同接口需要不同的字段。假设 user 表包含 id
, created_at
, updated_at
, username
, password
, email
字段,一个接口需要 id
和 username
,另一个接口需要 username
和 email
,项目为普通的 mvc 架构,controller 层提供接口,service 层对接 controller 和数据库,现在我能想到的有三种方式,不知道大家平时都怎么使用。
1 的问题在于需要做额外的赋值操作,2 的话入参结构有不确定性,可能引起问题,3 的话主要是会多些重复代码,但是能保证方法返回可预期,个人比较倾向方法 3 。 其实还有方法 4 就是什么都不处理都返回去,让调用方筛选,不过这个被直接 pass 了。
1
lhx2008 2020-04-23 15:57:17 +08:00 via Android
把隐藏的字段置空,序列化的时候隐藏
|
2
lhx2008 2020-04-23 15:59:35 +08:00 via Android
第二个是 controller 序列化的时候加一个策略,传入一个配置来控制序列化器的行为
|
3
lhx2008 2020-04-23 16:00:30 +08:00 via Android
第三个方法就是配多个 VO 对象,在 controller 转换
|
5
cxe2v 2020-04-23 16:48:43 +08:00
1,3 都可,不建议用 2
|
6
KentY 2020-04-23 16:53:28 +08:00
为什么不能把包含所有字段的 object 给不同请求方呢? 他不需要可以不用呀.
如果一些信息的保密 /屏蔽是必须的, 那不管怎么都需要另外一步, 要么屏蔽相关信息, 要么 convert into other objects |
7
johnj 2020-04-23 17:02:25 +08:00
如果你用的是 Spring MVC,那么可以用 Jackson 的 JSON View 注解 @JsonView
1 做一个分类的类(名称随便) public class Views { public static class Public { } public static class Internal { } } 2 根据分组 在 User 对象属性上加注解 如 @JsonView(Views.Public.class) 3 在 controller 方法上 确定要返回的分组 如 @JsonView(Views.Public.class) 参考: https://www.baeldung.com/jackson-json-view-annotation |
8
basefas OP @KentY 总体思想是尽量保持简洁,保持接口返回数据的最小化(说白了就是一种强迫症)。比如 user 表可能有 50 个字段,但是有时候可能只想要一个用户 ID,那返回数据中大部分就都没有用,还占带宽。还有就是例子中说的,可能会有 created_at 这种字段,一般情况下是不想直接返回给请求方的。
|
10
basefas OP @johnj 虽然没用过 Spring MVC,但是这个思想就是用一个 model 都查出来,然后在 controller 层处理数据吧
|
13
KentY 2020-04-23 17:09:09 +08:00
@basefas 如果没有实质的业务需求, 我觉得这样没太大必要. 返回值简捷并不算简捷(从某种意义讲).
比如需要 id, uid 的请求某天说, 我们想要姓氏, 那你后端就要重新改动部署. 这是完全没必要的. 至于带宽性能方面, 我不知道你们的项目是多么的 performance critical, 按一般情况讲, 这点带宽不算什么. 当然了, 我没了解你的项目需求, 只是说看到这个问题的一般感觉. 特殊情况是需要特殊对待. |
16
wutiantong 2020-04-23 17:51:55 +08:00
记好 kiss 原则
|
17
vitoliu 2020-04-23 17:53:47 +08:00
public class Simple{}
public class Medium extends Simple{} public class Hard extends Medium{} |
18
WUWENZE 2020-04-23 18:04:12 +08:00
这种需求我弄过,使用的是注解+拦截器,内部实现是 Fastjson 的 JSONSerializer
最终的效果就像这样 ```java @ApiResponseFilters({ // @ApiResponseFilter(clazz = UserVO.class, includeFields = "id,name,nickname,photo,type"), // @ApiResponseFilter(clazz = UserGroupVO.class, includeFields = "id") }) ``` |
19
aguesuka 2020-04-23 18:06:10 +08:00 via Android
我也有类似需求。系统有 3 张核心表,这三张核心表 join 其他十多张表可以查出来一条完整的数据。系统里大部分操作就是核心表 join 若干非核心表分页条件动态查询。现在我就想写一个 god 方法,根据前台要查的字段,要过滤的条件自动生成最优 sql,想了想难度不亚于实现个 orm 还是算了。
|
20
WUWENZE 2020-04-23 18:08:49 +08:00
@aguesuka 你可能需要的是 https://graphql.cn/
|
21
WUWENZE 2020-04-23 18:13:57 +08:00
@aguesuka 或者这个 http://apijson.org/
|
22
PopRain 2020-04-23 18:16:23 +08:00
如果是 c# ,分别返回不同对象很简单,就动态声明一个对象,包括需要的对象属性即可。java 不熟
|
23
Cmdhelp 2020-04-23 18:21:43 +08:00
一个接口一个方法,不混用
|
24
MOONYANYI 2020-04-23 18:49:43 +08:00
![Snipaste_2020-04-23_18-46-31.png]( )
|
25
yafoo 2020-04-23 19:54:40 +08:00 via Android
方法 2,动态传参,最合理。
方法 1,造成很多多余字段。 方法 3,部分接口可以使用。 |
26
pastgift 2020-04-23 20:20:52 +08:00 via iPhone
调用方指定需要的字段,统一过滤返回字段,合并成一个接口。
不能面向前端写后端,一个需求一个接口这么做,后端本身要自洽 |
27
xuanbg 2020-04-23 20:42:59 +08:00
返回使用不同的 dto 即可,不同类型的转换可以用 A 对象序列化后再反序列化为 B 来转,不需要一个个 get/set
|
28
no1xsyzy 2020-04-23 21:19:42 +08:00
@basefas #15 你这样强行缩略并不优雅
Premature optimization is the root of all evil. |
29
neilq 2020-04-23 21:44:11 +08:00 1
我是 1,3 结合着来的,
关于 1,我不是手动对两个 object 赋值,而是用了相应 mapper 库,c#的话用 AuthMapper 。 但是 1 不能解决返回指定字段,一开始我是让前端参数指定需要的字段,动态得只返回相应字段。后来觉得没有必要,而是根据业务情况,拆分成不同接口,这样语义化比较清晰。基础 get 接口返回一般性的基础字段,最多十几个把。其他字段可能只是具体的某一项业务用到,根据业务语义拆分接口,使用不同的 dto 。 另外补充一句,对于一个对象或者分页类几十条数据,10 个字段和 50 个字段在 http 上的性能损耗几乎可以忽略。对于一次返回几百几千条数据的可以单独优化,没必要在框架上做抽象。 |
30
buffzty 2020-04-24 10:16:01 +08:00
我是这样弄的, 查询的时候可以带上 scene 参数. 默认是 defaultScene, 普通人获取自己的详情就是 default, 管理员获取就是 adminScene. 注意要对 scene 做权限检查
|