已经学了两年的MVC了,但是有些概念还是很模糊,希望能在这里寻找到答案。
我曾经看到有人说Controller不负责数据处理,全部交给我们的Service来处理,网页前端传回来是什么数据类型,就直接把数据类型转发到Service,然后由Service来处理;但是又有另外一种声音说有时候会同时调用多个Service,如果在Controller就将对象封装好了,就免于在Service的方法中多次封装。
另外还有一个问题就是关于Controller与Service的交互问题。
我们为了前端的客户交互良好,往往会通过Controller向前端返回一些错误提示,比如用户名已存在,用户名和密码不匹配等等。可是处理业务逻辑我们是放在Service层,那么如果把一个login(String username,String password)方法的返回值设定为boolean就无法返回多种错误,但是如果返回String类型,就需要设定一些基本的字典。
我自己“奇思妙想”,我在Service中通过抛出我自定义的一些RuntimeException,然后在Controller中通过TryCatch来处理不同的错误,但是我自己认为这种抛出异常的方式不妥。最近就陷入了迷茫,马上就要开始做下一个项目了。希望各位能帮我解答一下迷惑。
感谢。
我们项目里分了三层:
表现层:Spring MVC,负责接收Http请求、展现(返回)结果、简单校验
App层:提供应用层的功能,比如导入、导出、复杂校验
Domain层:处理业务逻辑,比如一些Service
调用顺序是单项的:Controller->App->Domain
且感知关系为:Controller->App->Domain,即下层不感知上层
先回答你第一个问题:
你说的第一个问题我是否可以理解为,Http请求过来的参数不是Object,而是一堆基本类型,但是你的Service接收的参数是Object。正确的做法应该是,在Controller将“生”参数转换成Object对象,然后调用Service。
为何这样是正确的?因为Service属于Domain层,里面是业务逻辑,其接受的参数应该根据自己的需要而进行设计,不应该考虑Web层过来的参数是什么,这样才可以做到在不同场景下复用。
举个例子,你的Service应该可以被复用不同表现层环境下:
在一个Web程序中,用户传过来的参数是POST/GET形式给你的
在一个Web service程序中,用户传过来的参数是json或者SOAP
在一个Swing程序中,用户传过来的参数就是字符串
如果你将Service和具体某个表现层环境绑定,那么其方法参数肯定不稳定,结果就导致无法复用。
同理,Service的返回值也不应该和具体场景绑定。
在Spring MVC层面,Controller可以很方便的把参数转换成Object,相关文档
第二个问题:
这个问题可以分为三个:
1)简单的校验比如参数长度限制、非空判断等在哪里做?
简单校验利用Spring MVC的自身提供的机制做,相关文档,相关文档
2)和Service本身的业务逻辑平行的校验在哪里做,比如用户下单时判断其是否账号被禁用
我倾向于将这些逻辑校验放在App层做,Controller调用App,App调用两个不同的Service,将业务编织起来
3)和Service本身有关的业务逻辑校验怎么做
你举的是登录的例子,用异常告知调用方(Controller)处理结果没有任何问题。你也可以丰富Service的返回值达到这个目的,不过需要注意的是,Service的返回值的设计不能和表现层环境绑定,否则就不能复用了,这也就是为什么 @YaTou 提到了apache-shiro采用的是异常机制处理认证失败,因为只有这样才足够通用。