首页 新闻 搜索 专区 学院

Spring Web中拦截器(Interceptor)和控制器(Controller)各自应该有什么功能?

0
[已解决问题] 解决于 2021-10-21 21:23

我个人的习惯是拦截器检查用户请求是否正确。如果用户请求正确,则把请求交给控制器处理;如果请求不正确,则给用户返回错误信息。也就是说拦截器处理错误情况,控制器处理正常情况。但有时拦截器似乎越俎代庖做了控制器应该做的事情。

例如下面的例子。数据库中共有100篇文章,每页列表有10篇,共有10页文章列表。如果用户请求第1至10页文章列表,这属于正常情况,应该而且可以在控制器中处理,控制器从数据库中读取文章列表,拦截器只需要检查用户的页码参数是否正确。如果用户请求第11页文章列表,显然该页不存在。我认为这种错误情况应该在拦截器中处理,给用户返回404 页面。为了处理错误情况和减少数据库读写次数,读取文章总数和文章详情的操作都在拦截器中一次完成。

那么读取文章列表的操作应该在拦截器还是控制器中执行呢?

还有几种情况需要与向各位请教。

情况一。用户访问特定文章的详情页面,请求内包含文章id。是否需要在拦截器内检查该id对应的文章是否存在(该操作需要查询数据库)?如果是在控制器进行检查,如果用户请求的文章不存在,该如何在控制器内处理错误?

情况二。用户从服务器获取编辑文章的页面或向服务器提交删除文章的请求,该两种请求中都包含文章id。判断用户是不是文章的作者需要读取数据库,如果用户不是作者,则返回403页面。这一操作应该在拦截器中还是控制器中?

情况三。用户向服务器提交对文章的修改,该请求中包含文章id、文章标题和内容。有两点需要判断。第一,用户是不是文章的作者。这不是这一问题关注的重点。第二,判断用户提交的新文章与数据库中的内容是否相同,如果相同,则给用户返回304(未改变)状态码,这需要读取数据库。校验文章内容是否改变这一操作应该在拦截器中还是控制器中执行呢?

Halloworlds的主页 Halloworlds | 菜鸟二级 | 园豆:209
提问于:2021-10-20 09:48
< >
分享
最佳答案
1

你的拦截器做的功能是不是过多了,拦截器的主要职责不是校验请求是否合法吗?比如说校验这个请求的地址是不是合法的,请求是否携带某些必备的信息等等,应该是一种通用的在请求之前的处理。
控制器只接受合法的请求,并对合法的请求中携带的参数进行校验、处理,然后调用service层,然后再返回。

奖励园豆:5
名字被用了呢 | 菜鸟二级 |园豆:207 | 2021-10-20 11:09

我再问问一些其他有关拦截器的问题吧。

用户从服务器获取编辑文章的页面或向服务器提交删除文章的请求,该两种请求中都包含文章id。判断用户是不是文章的作者需要读取数据库,如果用户不是作者,则返回403页面。这一操作应该在拦截器中还是控制器中?

用户向服务器提交对文章的修改,该请求中包含文章id、文章标题和内容。有两点需要判断。第一,用户是不是文章的作者。这不是这一问题关注的重点。第二,判断用户提交的新文章与数据库中的内容是否相同,如果相同,则给用户返回304(未改变)状态码,这需要读取数据库。校验文章内容是否改变这一操作应该在拦截器中还是控制器中执行呢?

Halloworlds | 园豆:209 (菜鸟二级) | 2021-10-20 19:03

@Halloworlds:
第一个,在控制器中
第二个,也是在控制器中
我是这样理解的,不应该在拦截器中调用service层。尽量保证只在controller层才可以调用service层。
拦截器不应该对参数做处理,也不应该校验参数。

名字被用了呢 | 园豆:207 (菜鸟二级) | 2021-10-21 16:57

@Halloworlds:
我觉的有一个很好的例子,就是跨域问题。对于跨域问题,有一个解决办法,就是让每一次请求都携带一个令牌。
拦截器,会将所有携带令牌并且令牌正确的请求放行,将其余所有的请求都拦截。我感觉这个很能体现拦截器的作用。
控制器,对请求的参数进行校验并处理,最典型的就是@RequestParam和@RequestBody两个参数注解对参数的校验。controller内部对入参和返回值进行处理。
你所说的问题,1. 不是共性的问题,不是绝大部分接口都需要的 2. 对于不同的操作包含不同的相应结果,拦截器处理起来也会特别麻烦

名字被用了呢 | 园豆:207 (菜鸟二级) | 2021-10-21 17:04

@名字被用了呢: 我会把这些错误移到拦截器中处理是因为我不知道如何在控制器方法中处理错误。如果上面这些错误应该在控制器中处理,那么应该如何给用户返回错误页呢(例如找不到文章给用户返回404页面、用户不是文章的作者给用户返回403页面等)?(这个问题可能有些弱智,但是我没有学到怎么在控制器方法中处理错误)

Halloworlds | 园豆:209 (菜鸟二级) | 2021-10-21 19:36

@Halloworlds:
不要给客户错误的页面,错误了,就告诉他,你点错了,不要出现什么404 500之类的页面。
比如说不是他写的文章,他要修改,那你就告诉前端,这不是你的文章,你不能修改。
就和你那数据是一样的,只不过,把数据变成了一个文本。
之前返回给的data里面是各种各样的数据,如果出错了,就直接放一个字符串给前端就好了

名字被用了呢 | 园豆:207 (菜鸟二级) | 2021-10-21 20:50
其他回答(2)
0

读取文章列表的操作

持久化层中执行,Repository、Service、DAO等,
controller只是做参数校验、传入参、返回出参

快乐的凡人721 | 园豆:1366 (小虾三级) | 2021-10-20 09:54

我当然知道数据库的操作应该使用Repository、Service、DAO等,我想问的是应该在拦截器还是控制器调用DAO方法查询数据库?

支持(0) 反对(0) Halloworlds | 园豆:209 (菜鸟二级) | 2021-10-20 10:09

@Halloworlds:
controller。

支持(0) 反对(0) 快乐的凡人721 | 园豆:1366 (小虾三级) | 2021-10-20 10:36
1

要慎重,最好还是如楼上所说三层架构,尽量不要在拦截器进行数据交互。
还有返回404页面不友好,尽量是页面实现,数据空。
如果总10页,前端应该不会传11这个页码,即使传了也显示空数据。
若非要这么设计开发,读取文章列表的操作还是不要放在拦截器中。拦截器中进行数据库交互会每次url请求都会进入,耗性能。拦截器,过滤器的目的是对一些共性操作统一处理。很明显这业务场景不是共性的,仅是现在这个业务场景需要用到。所以不推荐放在拦截器中进行读取文章列表的操作。

绝不是木头 | 园豆:506 (小虾三级) | 2021-10-20 10:07
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册