一些程序封装的疑问

2020 年 4 月 23 日
 basefas

例如一个获取用户信息的功能,但是可能不同接口需要不同的字段。假设 user 表包含 id, created_at, updated_at, username, password, email 字段,一个接口需要 id 和 username,另一个接口需要 username 和 email,项目为普通的 mvc 架构,controller 层提供接口,service 层对接 controller 和数据库,现在我能想到的有三种方式,不知道大家平时都怎么使用。

  1. service 层方法查出 user 的全部字段,在 controller 层通过创建新 object,将所需字段赋值给 object
  2. service 层方法参数和返回值设置为 interface,在 controller 层调用时将需要查询的 object 作为参数传入
  3. service 层写两个方法,分别返回不同 object

1 的问题在于需要做额外的赋值操作,2 的话入参结构有不确定性,可能引起问题,3 的话主要是会多些重复代码,但是能保证方法返回可预期,个人比较倾向方法 3 。 其实还有方法 4 就是什么都不处理都返回去,让调用方筛选,不过这个被直接 pass 了。

4221 次点击
所在节点    程序员
30 条回复
lhx2008
2020 年 4 月 23 日
把隐藏的字段置空,序列化的时候隐藏
lhx2008
2020 年 4 月 23 日
第二个是 controller 序列化的时候加一个策略,传入一个配置来控制序列化器的行为
lhx2008
2020 年 4 月 23 日
第三个方法就是配多个 VO 对象,在 controller 转换
basefas
2020 年 4 月 23 日
@lhx2008 你说的这些都是在 service 层把所有字段都查出来,在 controller 层做格式化是么?
cxe2v
2020 年 4 月 23 日
1,3 都可,不建议用 2
KentY
2020 年 4 月 23 日
为什么不能把包含所有字段的 object 给不同请求方呢? 他不需要可以不用呀.
如果一些信息的保密 /屏蔽是必须的, 那不管怎么都需要另外一步, 要么屏蔽相关信息, 要么 convert into other objects
johnj
2020 年 4 月 23 日
如果你用的是 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
basefas
2020 年 4 月 23 日
@KentY 总体思想是尽量保持简洁,保持接口返回数据的最小化(说白了就是一种强迫症)。比如 user 表可能有 50 个字段,但是有时候可能只想要一个用户 ID,那返回数据中大部分就都没有用,还占带宽。还有就是例子中说的,可能会有 created_at 这种字段,一般情况下是不想直接返回给请求方的。
lhx2008
2020 年 4 月 23 日
@basefas 如果对象查询次数不多的话不用专门写 service
basefas
2020 年 4 月 23 日
@johnj 虽然没用过 Spring MVC,但是这个思想就是用一个 model 都查出来,然后在 controller 层处理数据吧
johnj
2020 年 4 月 23 日
@basefas 对的 service 不应该管上层的事
johnj
2020 年 4 月 23 日
@basefas 哦 你不是 java 栈的 那这些方法应该不适用了 看你用的序列化库有什么样的支持吧
KentY
2020 年 4 月 23 日
@basefas 如果没有实质的业务需求, 我觉得这样没太大必要. 返回值简捷并不算简捷(从某种意义讲).
比如需要 id, uid 的请求某天说, 我们想要姓氏, 那你后端就要重新改动部署. 这是完全没必要的. 至于带宽性能方面, 我不知道你们的项目是多么的 performance critical, 按一般情况讲, 这点带宽不算什么.

当然了, 我没了解你的项目需求, 只是说看到这个问题的一般感觉. 特殊情况是需要特殊对待.
basefas
2020 年 4 月 23 日
@johnj 嗯嗯,也是一种思路
basefas
2020 年 4 月 23 日
@KentY 嗯,你说的有道理,我也没有具体的需求,只是考虑在没有限制条件的情况下,怎么写才比较优雅。
wutiantong
2020 年 4 月 23 日
记好 kiss 原则
vitoliu
2020 年 4 月 23 日
public class Simple{}
public class Medium extends Simple{}
public class Hard extends Medium{}
WUWENZE
2020 年 4 月 23 日
这种需求我弄过,使用的是注解+拦截器,内部实现是 Fastjson 的 JSONSerializer

最终的效果就像这样
```java

@ApiResponseFilters({ //
@ApiResponseFilter(clazz = UserVO.class, includeFields = "id,name,nickname,photo,type"), //
@ApiResponseFilter(clazz = UserGroupVO.class, includeFields = "id")
})



```
aguesuka
2020 年 4 月 23 日
我也有类似需求。系统有 3 张核心表,这三张核心表 join 其他十多张表可以查出来一条完整的数据。系统里大部分操作就是核心表 join 若干非核心表分页条件动态查询。现在我就想写一个 god 方法,根据前台要查的字段,要过滤的条件自动生成最优 sql,想了想难度不亚于实现个 orm 还是算了。
WUWENZE
2020 年 4 月 23 日
@aguesuka 你可能需要的是 https://graphql.cn/

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/665355

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX