Yur*_*riy 12 java model-view-controller spring-mvc
我已经阅读了很多关于服务层和控制器之间差异的理论,我对如何在实践中实现这一点有一些疑问.服务层和控制器的一个答案:谁负责什么?说:
我尝试限制控制器执行与验证http参数相关的工作,决定使用什么参数调用什么服务方法,在httpsession或请求中放入什么,重定向或转发到哪个视图,或类似的Web相关内容.
红旗:如果出现以下情况,我的控制器架构可能会变坏:
Controller向服务层发出过多请求.Controller向服务层发出许多不返回数据的请求.Controller在不传递参数的情况下向Service层发出请求.
目前我正在使用Spring MVC开发一个Web应用程序,我有这样的方法来保存更改的用户的电子邮件:
/**
* <p>If no errors exist, current password is right and new email is unique,
* updates user's email and redirects to {@link #profile(Principal)}
*/
@RequestMapping(value = "/saveEmail",method = RequestMethod.POST)
public ModelAndView saveEmail(
@Valid @ModelAttribute("changeEmailBean") ChangeEmailBean changeEmailBean,
BindingResult changeEmailResult,
Principal user,
HttpServletRequest request){
if(changeEmailResult.hasErrors()){
ModelAndView model = new ModelAndView("/client/editEmail");
return model;
}
final String oldEmail = user.getName();
Client client = (Client) clientService.getUserByEmail(oldEmail);
if(!clientService.isPasswordRight(changeEmailBean.getCurrentPassword(),
client.getPassword())){
ModelAndView model = new ModelAndView("/client/editEmail");
model.addObject("wrongPassword","Password doesn't match to real");
return model;
}
final String newEmail = changeEmailBean.getNewEmail();
if(clientService.isEmailChanged(oldEmail, newEmail)){
if(clientService.isEmailUnique(newEmail)){
clientService.editUserEmail(oldEmail, newEmail);
refreshUsername(newEmail);
ModelAndView profile = new ModelAndView("redirect:/client/profile");
return profile;
}else{
ModelAndView model = new ModelAndView("/client/editEmail");
model.addObject("email", oldEmail);
model.addObject("emailExists","Such email is registered in system already");
return model;
}
}
ModelAndView profile = new ModelAndView("redirect:/client/profile");
return profile;
}
Run Code Online (Sandbox Code Playgroud)
您可以看到我对服务层有很多请求,我从控制器重定向 - 这是业务逻辑.请显示此方法的更好版本.
另一个例子.我有这个方法,它返回用户的个人资料:
/**
* Returns {@link ModelAndView} client's profile
* @param user - principal, from whom we get {@code Client}
* @throws UnsupportedEncodingException
*/
@RequestMapping(value = "/profile", method = RequestMethod.GET)
public ModelAndView profile(Principal user) throws UnsupportedEncodingException{
Client clientFromDB = (Client)clientService.getUserByEmail(user.getName());
ModelAndView model = new ModelAndView("/client/profile");
model.addObject("client", clientFromDB);
if(clientFromDB.getAvatar() != null){
model.addObject("image", convertAvaForRendering(clientFromDB.getAvatar()));
}
return model;
}
Run Code Online (Sandbox Code Playgroud)
方法convertAvaForRendering(clientFromDB.getAvatar())被放置在这个控制器的超类中,它是正确放置这个方法,还是他必须放在服务层?
请帮助,这对我来说非常重要.
Art*_*eda 12
一个Spring Controller一般是绑在春天API(与像类Model,ModelAndView...),或在Servlet API( HttpServletRequest,HttpServletResponse...).方法可以返回String已解析为模板名称的结果(JSP ...).Controller他们肯定偏向于Web GUI,并且非常依赖Web技术.
Service另一方面,s 应该考虑到业务逻辑而不是客户端的假设.我们可以远程服务,将其公开为Web服务,实现Web前端或Swing客户端.A Service 不应该依赖于Spring MVC,Servlet API等.这样,如果您需要重新定位应用程序,则可以重用大多数业务逻辑.
至于关于从控制器层调用服务层的次数太多的注释,它主要是性能问题,恕我直言是不同的.如果每次调用服务层都会查询数据库,则可能会遇到性能问题.服务层和控制器层没有在同一个JVM中运行,您也可能遇到性能问题.这是设计应用程序的另一个非常重要的方面,但它表明您应该对服务调用进行外观,以便为控制器层提供粗粒度的操作.
在这两个例子中,你为什么需要演员Client?那是代码味道.
由于对服务层的调用也是建立数据库事务边界的调用,因此进行多次调用意味着它们在不同的事务中执行,因此不一定彼此一致.
这是不鼓励多次通话的原因之一.@ArthurNoseda在他的回答中提到了其他好的理由.
在您的第一种情况下,应该只对服务层进行一次调用,例如:
if (changeEmailResult.hasErrors()) {
return new ModelAndView("/client/editEmail");
}
try {
clientService.updateUserEmail(user.getName(),
changeEmailBean.getCurrentPassword(),
changeEmailBean.getNewEmail());
} catch (InvalidPasswordException unused) {
ModelAndView model = new ModelAndView("/client/editEmail");
model.addObject("wrongPassword", "Password doesn't match to real");
return model;
} catch (DuplicateEmailException unused) {
ModelAndView model = new ModelAndView("/client/editEmail");
model.addObject("email", oldEmail);
model.addObject("emailExists", "Such email is registered in system already");
return model;
}
refreshUsername(newEmail);
return new ModelAndView("redirect:/client/profile");
Run Code Online (Sandbox Code Playgroud)
您也可以使用返回值而不是异常.
如您所见,这将委托将电子邮件更改为服务层的业务逻辑,同时将所有与UI相关的操作保留在控制器所属的位置.
| 归档时间: |
|
| 查看次数: |
11710 次 |
| 最近记录: |