1. MVC思想的演变:
JavaWeb与MVC
JavaWeb的经历了JSP Model1、JSP Model1二代、JSP Model2三个时期。
JSP Model1第一代
JSP Model1是JavaWeb早期的模型,它适合小型Web项目,开发成本低!Model1第一代时期,服务器端只有JSP页面,所有的操作都在JSP页面中,连访问数据库的API也在JSP页面中完成。也就是说,所有的东西都耦合在一起,对后期的维护和扩展极为不利。
JSP Model1第二代
JSP Model1第二代有所改进,把业务逻辑的内容放到了JavaBean中,而JSP页面负责显示以及请求调度的工作。虽然第二代比第一代好了些,但还让JSP做了过多的工作,JSP中把视图工作和请求调度(控制器)的工作耦合在一起了。
JSP Model2
JSP Model2模式已经可以清晰的看到MVC完整的结构了。
l JSP:视图层,用来与用户打交道。负责接收用来的数据,以及显示数据给用户;
l Servlet:控制层,负责找到合适的模型对象来处理业务逻辑,转发到合适的视图;
l JavaBean:模型层,完成具体的业务工作,例如:开启、转账等。
好处在于其中的controller和view的方式可以改变而不影响后面的model层的业务;
JavaWeb经典三层框架
我们常说的三层框架是由JavaWeb提出的,也就是说这是JavaWeb独有的!
所谓三层是表述层(WEB层)、业务逻辑层(Business Logic),以及数据访问层(Data Access)。
l WEB层:包含JSP和Servlet等与WEB相关的内容;
l 业务层:业务层中不包含JavaWeb API,它只关心业务逻辑;
l 数据层:封装了对数据库的访问细节;
2.SpringMVC的核心组件
中央处理器、key-value结构找到对应的处理器、适配转换成需要的方法、解析业务返回的页面字符串名称、页面渲染
3.SpringMVC的请求过程
1.客户端往后端发送请求;
2.DispatcherServlet进行请求筛选,主要筛选两种请求:① *.do ② 带/的请求,DispatcherServlet对请求URL(统一资源定位符)进行解析,得到URI(请求资源标识符)
3.因为还需要对响应的请求进行拦截,所以请求HanderMapping ,是一个Key-Value的结构,返回一个包含拦截器和处理器的复合对象HandlerExcutionChain;
4.由于需要对HandlerExcutionChain转换成handler,采用适配器模式进行一次转换handlerAdaptor;
5.请求相应的handler,业务处理后返回相应的页面名称和数据;
6.请求viewResolver对返回的数据和页面进行组合,返回view对象(ViewResolver接口定义了如何通过view 名称来解析对应View实例的行为,即:如何把控制器返回的“视图名 字符串” 解析为View实例,并渲染为HTML、PDF后推向浏览器);
7.请求view返回页面;(View接口表示一个响应给用户的视图,例如jsp文件,pdf文件,html文件等)
-
DispatcherServlet会加载所有的viewResolver到一个list中,并按照优先级进行解析。
注意:①order中的值越小,优先级越高。
②而id为viewResolver的viewResolver的优先级是最低的。
- 如果某个解析器没有找到合适的视图,Spring会在上下文中寻找是否配置了其它的解析器。 如果有,它会继续进行解析,否则,Srping会抛出一个
Exception
。
4. SpringMVC 的常用注解有哪些?
1. @PathVariable
用于获取路径参数,@RequestParam
用于获取查询参数
2. @RequestBody
. 用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分并且Content-Type 为 application/json 格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上去。系统会使用HttpMessageConverter
或者自定义的HttpMessageConverter
将请求的 body 中的 json 字符串转换为 java 对象。
一个请求方法只可以有一个@RequestBody
,但是可以有多个@RequestParam
和@PathVariable
3. @RequestMapping
:用于处理 URL 映射的的注解,既可用于类上,也可用于方法上,当作用于类上时则表示当前类中的所有响应方法都是以这个 url 作为父路径;
4. @ResponseBody
:将 Java 对象转为 json 格式的数据;
5. @RestController 和 @Controller
Controller
返回一个页面:
单独使用Controller
不加@ResponseBody
使用的话就要经过视图解析流程 (ViewResolve),最后返回给到前端一页面,这种情况属于比较传统的 Spring MVC 应用,对应前后端不分离的情况;- 但
@RestController
只返回对象,对象数据直接以 JSON 或 XML 形式写入 HTTP 响应(Response)中,这种情况属于 RESTful Web服务,这也是目前日常开发所接触的最常用的情况(前后端分离)。 - 项目中的实际使用情况:在进行用户密码验证时,返回验证的错误类型,前段显示alarm;
5 . 如何解决 POST 请求和 GET 请求中文乱码问题?
- 解决 POST 请求乱码问题:在 web.xml 中配置一个 CharacterEncodingFilter 过滤器,设置成 utf-8 ;
- GET 请求中出现中文乱码,讲真在url 中传递中文,就不是什么明智之举,最好不要这用做!
但是事情已经发生了,总得要解决的:- 修改 Tomcat 配置文件;
- 在拼接 url 的时候先做一个编码工作,然后将编码后生成的 url 进行拼接,之后再发送请求,然后再服务端拿到数据后做一次反编码的工作;
- 最好就是定义一个字典,在发送 url 的get 请求之前先查询一下要拼接的 中文 字段对应的字典值,然后用字典值进行传输,完事了再在服务端做解析;
6. SpringMVC 制器是不是单例模式,如果是,有什么问题,怎么解决?
是单例模式,之前在 Spring 篇章里面有说过控制层和Service 层以及 DAO 层一般是无状态的实例,不涉及数据的增删改等操作,只有简单的查询操作,那么就是线程安全的,所以解决方案就是:在控制器里面不要写可变的状态量,如果需要这些可变的状态量,那么可以通过 ThreadLocal
进行解决,为每个线程提供一个独立的变量副本,进行数据操作;
7.SpringMVC 怎么样设定重定向和转发的?
- 转发:在返回值前面加:“forward”–>
"forword:index.do?name=2"
- 重定向:在返回值前面加:“redirect” –>
“redirect:http://www.baidu.com”
转发可以携带参数、不改变原来的url、一般在服务器的内部页面间转发;
重定向不可以携带参数、产生新的url请求、可以在服务器外部页面进行请求;
8.拦截器和过滤器的区别?
参与流程:
Filter->Interceptor.preHandle->Handler->Interceptor.postHandle->Interceptor.afterCompletion->Filter
实现方式:
filter:自定义类 实现 filter接口,重写init 、dofilter、destroy方法
interceptor: 自定义类实现 handlerInterceptor接口,重写prehandle、posthandle、aftercomplation方法
注册方式
filter注册方式:
1.webfilter过滤+@ServletComponentScan注解开启;@order+@component可以决定优先顺序但是指定的webfilter过滤会失效;
- 精确过滤匹配 ,比如/index.jsp /myservlet1
- 后缀过滤匹配,比如.jsp、.html、*.jpg
- 通配符过滤匹配/**,表示拦截所有。
2.@configuration+@Bean
public FilterRegistrationBean<AuthFilter> RegistAuth(){}可以设置优先级,同时设置过滤url
interceptor注册方式:
@configuration,实现webmvcConfigurer接口,并重写 addInterceptors方法。可以设置优先级,同时设置过滤url
执行顺序:
filter(默认按照名称的字母先后顺序执行),除非指定;
interceptor(默认按照加载先后顺序执行),除非指定;
方法执行:
filter主要是在dofilter中执行,同时结尾调用filterchain.dofilter执行下一个过滤器;
interceptor:prehandle:调用执行器之前执行;posthandle调用执行器之后执行但在渲染之前;aftercomponent,再回送请求之前;
执行顺序:
1. posthandle、aftercomponent都是prehandle的倒序
2.prehandle没通过不执行其他的两个方法;
3.多个拦截器任何一个没通过,所有的posthandle都不会执行
4.prehandle执行且通过,才会有aftercomponent;
使用目的:
过滤器应用场景
- 过滤敏感词汇(防止sql注入)
- 设置字符编码
- URL级别的权限访问控制
- 压缩响应信息
拦截器应用场景
拦截器本质上是面向切面编程(AOP),符合横切关注点的功能都可以放在拦截器中来实现,主要的应用场景包括:
- 登录验证,判断用户是否登录。
- 权限验证,判断用户是否有权限访问资源,如校验token
- 日志记录,记录请求操作日志(用户ip,访问时间等),以便统计请求访问量。
- 处理cookie、本地化、国际化、主题等。
- 性能监控,监控请求处理时长等。
- 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现)
拦截器和过滤器的区别
1.过滤器是servlet中的对象, 拦截器是框架中的对象
2.过滤器实现Filter接口的对象, 拦截器是实现HandlerInterceptor
3.过滤器是用来设置request,response的参数,属性的,侧重对数据过滤的。
拦截器是用来验证请求的,能截断请求。
4.过滤器是在拦截器之前先执行的。
5.过滤器是tomcat服务器创建的对象
拦截器是springmvc容器中创建的对象
6.过滤器是一个执行时间点。
拦截器有三个执行时间点
7.过滤器可以处理jsp,js,html等等
拦截器是侧重拦截对Controller的对象。 如果你的请求不能被DispatcherServlet接收, 这个请求不会执行拦截器内容
8.拦截器拦截普通类方法执行,过滤器过滤servlet请求响应
9. SpringMVC 怎么和AJAX相互调用的?
通过 Jackson 框架可以将 Java 中的对象直接转换为 json 对象:
- 加入 Jackson.jar 包
- 在配置文件中配置 json 的映射
- 在接受 ajax 方法里面可以直接返回对象,但是需要使用
@ResponseBody
注解;
10. 怎样在方法里面得到Request,或者Session?
直接在方法的形参中声明 request,SpringMVC 就自动把 request 对象传入。
11. 如果想在拦截的方法里面得到从前台传入的参数,怎么得到?
直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样。
12. 如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象?
直接在方法形参中声明这个对象,SpringMVC 就自动会把属性赋值到这个对象里面。
13. SpringMVC 中函数的返回值是什么?
返回值可以有很多类型,有String,ModelAndView。ModelAndView类把视图和数据都合并的一起的,但一般用String比较好。
14. SpringMVC 用什么对象从后台向前台传递数据的?
- 将数据绑定到 request
- 返回 ModelAndView;
- 通过ModelMap对象,可以在这个对象里面调用put方法,把对象加到里面,前端就可以通过el表达式拿到。
- 绑定数据到 Session中;
15.两个方法的映射能否处理相同的url?
1. 同样的URL,不同的Method(Get、Put、Post、Delete)会被映射到各自的方法上处理,这就是Rest的魅力,没必要为每种操作定义不同URL(以前只有Post和Get,是做不到的)
2.同样的url不同的参数需要使用时可以用param,@GetMapping(value = "/api", params = {"operation", "sChallenge", "sResponse"}),param不同也可以使用同样的url;
2.基于类级别的根URL需唯一,两个类映射到同样的URL是不允许的,SprintBoot启动时就会报错。
16.Get、Put、Post、Delete的区别?
get查询,put更新,post新增,delete删除;
put是幂等操作,post不是;
17.url通配符有哪些?
我们还可以通过通配符对URL映射进行配置,通配符有“?”和“*”两个字符。其中“?”表示1个字符,“*”表示匹配多个字符,“**”表示匹配0个或多个路径。
例如:
“/helloworld/index?”可以匹配“/helloworld/indexA”、“/helloworld/indexB”,但不能匹配“/helloworld/index”也不能匹配“/helloworld/indexAA”;
“/helloworld/index*”可以匹配“/helloworld/index”、“/helloworld/indexA”、“/helloworld/indexAA”但不能匹配“/helloworld/index/A”;
“/helloworld/index/*”可以匹配“/helloworld/index/”、“/helloworld/index/A”、“/helloworld/index/AA”、“/helloworld/index/AB”但不能匹配 “/helloworld/index”、“/helloworld/index/A/B”;
“/helloworld/index/**”可以匹配“/helloworld/index/”下的多有子路径,比如:“/helloworld/index/A/B/C/D”;
如果现在有“/helloworld/index”和“/helloworld/*”,如果请求地址为“/helloworld/index”那么将如何匹配?Spring MVC会按照最长匹配优先原则(即和映射配置中哪个匹配的最多)来匹配,所以会匹配“/helloworld/index”
参考
1.JavaWeb中MVC模型的演变_web mvc的演进_午-夜的博客-优快云博客
2.Java面试系列之SpringMvc请求响应_01_哔哩哔哩_bilibili
3.https://www.cnblogs.com/jiangtao1218/p/10204861.html
4.https://www.cnblogs.com/it-mh/articles/10406475.html
5.Spring&SpringBoot常用注解总结 | JavaGuide(Java面试+学习指南)
7.@RestController vs @Controller
9.拦截器与过滤器详解,使用方式与注意事项,使用场景以及区别与联系_过滤器和拦截器的区别和使用场景_reresrse的博客-优快云博客
10.SpringBoot中使用过滤器_Lyzxii的博客-优快云博客
11.【SpringBoot】URL路径映射规则_weixin_33911824的博客-优快云博客
12. 使用RequestMapping处理同一url不同参数请求_requestmapping url参数_biuaxia的博客-优快云博客
13.总结get、put、post、delete的区别和用法_get post put_云庄clouder的博客-优快云博客