Ich beschäftige mich seit zwei Jahren mit MVC, aber einige Konzepte sind immer noch vage. Ich hoffe, ich kann hier die Antwort finden.
Ich habe einmal jemanden sagen sehen, dass der Controller nicht für die Datenverarbeitung verantwortlich ist und dass alles von unserem Dienst verwaltet wird. Welcher Datentyp auch immer vom Frontend der Webseite zurückgegeben wird, der Datentyp wird direkt an den Dienst weitergeleitet dann wird es vom Dienst verarbeitet, aber es gibt noch eine andere Stimme, die sagt, dass manchmal mehrere Dienste gleichzeitig aufgerufen werden. Wenn das Objekt im Controller gekapselt ist, wird es in der Dienstmethode mehrmals vermieden.
Eine weitere Frage betrifft die Interaktion zwischen Controller und Service.
Um eine gute Kundeninteraktion am Frontend sicherzustellen, geben wir häufig einige Fehlermeldungen über den Controller an das Frontend zurück, z. B. dass der Benutzername bereits vorhanden ist, Benutzername und Passwort nicht übereinstimmen usw. Allerdings verarbeiten wir die Geschäftslogik in der Service-Schicht. Wenn wir den Rückgabewert einer Login-Methode (String-Benutzername, String-Passwort) auf boolean setzen, können wir nicht mehrere Fehler zurückgeben. Wenn wir jedoch den String-Typ zurückgeben, müssen wir dies tun Legen Sie einige Grundeinstellungen fest.
Meine eigene „ausgefallene Idee“ ist, dass ich einige benutzerdefinierte RuntimeExceptions im Service auslöste und dann TryCatch im Controller verwende, um verschiedene Fehler zu behandeln, aber ich denke, dass diese Art des Auslösens von Ausnahmen unangemessen ist. Ich war in letzter Zeit verwirrt und beginne gerade mit der Arbeit an meinem nächsten Projekt. Ich hoffe, Sie können mir helfen, meine Verwirrung zu beseitigen.
Vielen Dank.
我们项目里分了三层:
表现层: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采用的是异常机制处理认证失败,因为只有这样才足够通用。
我觉得
Controller
不负责处理数据是正确的, 因为在spring-mvc
中Controller
是不能复用的, 但是如果你把业务逻辑抽象成Service
, 那么这个Service
就是可以复用的.至于你说的 "在Controller就将对象封装好了,就免于在Service的方法中多次封装" , 没太明白什么意思, 你每个
Service
需要什么参数,Controller
就给什么参数, 至于需要的参数是否需要封装成对象就可以自己权衡了.你所说的
login(String username,String password)
, 你想抽象成Service
用异常处理处理多种不同的结果, 这个我觉得完全没有问题, 而且我觉得非常好啊, 很多认证框架都用的这种方式, 至少我看的apache-shiro
就是用异常处理认证失败的不同情况的.第一个问题感觉没有标准答案,具体情况具体分析,逻辑分层清晰易于维护就好。
第二个问题的话,你这里给出的交互是隶属于权限控制的,一般用filter、aop、代理、反射等等方式实现代码收束都可以,异常也在这些集中控制的代码里扔一次就好,直接在Controller里硬编码我反倒觉得累赘。Service这一层更多的是调用Dao层的方法来实现一些复杂的涉及多表的业务逻辑处理,事务也放在这一层(当然现在框架把这事儿都干了),所以Service这一层一般不扔异常(参数验证在Controller以及之前的层次都做掉了因此不出现业务相关异常,而Dao把数据库相关的底层异常屏蔽了)。
当然这是个人看法,没有定式,还是那句话,分层清晰易于维护就好。
1、Controller默认是单例的,但可用@Scope(value = "prototype")替换
2、登录可以返回int啊,自己加个枚举
3、规定是在Service层处理逻辑,要看业务的吧,代码冗余度低些好,也好优化
大家观点会不同,做开发更多的还是优化改,降低冗余度,而不是必须要怎么做。。。
1,Controller应尽可能的不设计业务逻辑,只涉及交互
2,Service为可复用的业务逻辑
3,Controller为Service的上级调用方
4,你这个case可以在Service中返回固定的返回值,在Controller层做判断,并抛出你想相应的异常。
当然了这只是我们目前的做法,分享一下。。。
可以看看我这篇
AOP,MVC——Spring的学习以及对CodeIgniter的反思 /a/11...
建议逻辑放在service,我们最近在做分布式微服务架构,我们之前是放在controller层的,拆分的时候基本全部重新,另外有些app需要使用的接口如果放在controller就无法共用,蛋疼吧?
封装对象到底在Controller还是Service,还是要看具体的情况,个人认为如果是简单的参数在Controller中进行封装时是完全可以的,如果放到Service反而会显得很冗余,而且导致Service通用性变差;对于第二个问题,不容同意通过枚举或者不同的状态码来在Controller左做判断抛出异常,完全可以自己定义一套异常处理机制,直接在Service层抛出,项目有针对此类业务异常的处理机制,直接两将Service的错误信息和错误码返回到View层,让客户端根据状态码和错误信息作处理