SpringMVC面试题
1-10
1.谈谈你对 MVC 模式的理解?
MVC 是 Model — View — Controler 的简称,它是一种架构模式,它分离了表现与交互。它被分为三个核心部件:模型、视图、控制器。
Model(模型):是程序的主体部分,主要包含业务数据和业务逻辑。在模型层,还会涉及到用户发布的服务,在服务中会根据不同的业务需求,更新业务模型中的数据。
View(视图):是程序呈现给用户的部分,是用户和程序交互的接口,用户会根据具体的业务需求,在 View 视图层输入自己特定的业务数据,并通过界面的事件交互,将对应的输入参数提交给后台控制器进行处理。
Controller(控制器):Controller 是用来处理用户输入数据,以及更新业务模型的部分。控制器中接收了用户与界面交互时传递过来的数据,并根据数据业务逻辑来执行服务的调用和更新业务模型的数据和状态。
2.SpringMVC 的工作原理/执行流程?
SpringMVC通过前端控制器(DispatcherServlet)拦截并处理用户请求的
① 前端发送请求被前端控制器DispatcherServlet拦截 ② 前端控制器调用处理器映射器HandlerMapping对请求URL进行解析,解析之后返回调用给前端控制器 ③ 前端控制器调用处理器适配器处理调用链 ④ 处理器适配器基于反射通过适配器设计模式完成处理器(控制器)的调用处理用户请求 ⑤ 处理器适配器将控制器返回的视图和数据信息封装成ModelAndView响应给前端控制器 ⑥ 前端控制器调用视图解析器ViewResolver对ModelAndView进行解析,将解析结果(视图资源和数据)响应给前端控制器 ⑦ 前端控制器调用视图view组件将数据进行渲染,将渲染结果(静态视图)响应给前端控制器 ⑧ 前端控制器响应用户请求
3.SpringMVC 的核心组件有哪些?
DispatcherServlet
前端控制器、总控制器
作用:接收请求,协同各组件工作、响应请求
HandlerMapping
处理器映射
作用:负责根据用户请求的URL找到对应的Handler
可配置 SpringMVC提供多个处理器映射的实现,可以根据需要进行配置
HandlerAdapter
处理器适配器
作用:按照处理器映射器解析的用户请求的调用链,通过适配器模式完成Handler的调用
Handler
处理器/控制器
由工程师根据业务的需求进行开发
作用:处理请求
ModelAndView
视图模型
作用:用于封装处理器返回的数据以及相应的视图
ModelAndView = Model + View
ViewResolver
视图解析器
作用:对ModelAndView进行解析
可配置 SpringMVC提供多个视图解析器的实现,可以根据需要进行配置
View
视图
作用:完成数据渲染
4.SpringMVC 常用的注解有哪些?
@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径;
@RequestBody:注解实现接收 HTTP 请求的 json 数据,将 json 转换为 Java 对象;
@ResponseBody:注解实现将 Controller 方法返回对象转化为 json 对象响应给客户。
5.@RequestMapping 的作用是什么?
@RequestMapping是Spring MVC框架中的注解,用于将请求URL映射到相应的处理方法上。它的作用是定义一个URL和处理方法之间的映射关系,以便当请求达到时,能够找到正确的处理方法来处理请求。
@RequestMapping注解可以用于类级别和方法级别上。在类级别上使用时,它指定了该类所有处理方法的父路径,而在方法级别上使用时,它定义了特定请求URL的映射。
通过@RequestMapping注解,我们可以指定以下内容:
请求的URL路径:可以是固定的路径,如"/user";也可以包含变量,如"/user/{id}",其中{id}作为路径变量,会被具体的值替代。
请求的HTTP方法:可以限制请求的方法类型,如GET、POST、PUT、DELETE等。可以使用@RequestParam注解来绑定请求参数。
请求的其他属性:可以设置请求的媒体类型(produces、consumes)、请求的头部信息(headers)等。
示例:
@Controller @RequestMapping("/user") public class UserController { @RequestMapping(value = "/{id}", method = RequestMethod.GET) public String getUser(@PathVariable("id") int userId) { // 处理获取用户信息的逻辑 return "user"; } @RequestMapping(value = "/add", method = RequestMethod.POST) public String addUser(@RequestParam("name") String name, @RequestParam("age") int age) { // 处理添加用户的逻辑 return "redirect:/user"; } }在上面的示例中,类级别的@RequestMapping注解定义了"/user"作为所有处理方法的父路径。方法级别的@RequestMapping注解指定了不同的URL映射和请求方法类型。
总之,@RequestMapping注解在Spring MVC中起到了定义请求URL映射的作用,使得请求能够被正确地路由到对应的处理方法上进行处理。
6.如何解决 POST 请求中文乱码问题,GET 的又如何处理呢?
1.解决 POST 请求乱码问题:在 web.xml 中配置一个 CharacterEncodingFilter 过滤器,设置成 utf-8;
2.GET 请求中文参数出现乱码解决方法有两个:
(1)修改 tomcat 配置文件添加编码与工程编码一致,如下:
<ConnectorURIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort>(2)对参数进行重新编码:
String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
7.SpringMVC 的控制器是不是单例模式,如果是会有什么问题,怎么解决?
是单例模式,所以在多线程访问的时候有线程安全问题。
可以采取以下几种方式来解决:
避免使用成员变量:单例控制器的成员变量是共享的,可能导致多个请求之间的数据冲突。尽量避免在控制器中使用成员变量,而是在处理方法中使用局部变量。
使用ThreadLocal:会影响性能
8.SpringMVC 怎么样设定重定向和转发的?
控制器响应同步请求
同步请求:form、超链接
处理同步请求的方法的返回类型定义为String或者ModelAndView,以实现页面的跳转
返回类型为String
转发
@RequestMapping("/add") public String addBook(String name, String author, double price){ System.out.println("---book add"); return "/tips.jsp"; } // "/tips.jsp" 的"/"表示上级目录重定向
@RequestMapping("/add") public String addBook(String name, String author, double price){ System.out.println("---book add"); return "redirect:/tips.jsp"; }
返回类型为 ModelAndView
转发
@RequestMapping("/add") public ModelAndView addBook(String name, String author, double price){ System.out.println("---book add"); ModelAndView modelAndView = new ModelAndView("/tips.jsp"); return modelAndView; }重定向
@RequestMapping("/add") public ModelAndView addBook(String name, String author, double price){ System.out.println("---book add"); ModelAndView modelAndView = new ModelAndView("redirect:/tips.jsp"); return modelAndView; }控制器响应异步请求
异步请求:ajax请求
使用response中的输出流进行响应
控制器方法的返回类型为
void
控制器方法添加
HttpServletResponse response
参数在方法中通过response获取输出流,使用流响应ajax请求
@RequestMapping("/update") public void update(@RequestBody Book book, HttpServletResponse response) throws IOException { System.out.println("---book update"); System.out.println(book); //使用ObjectMapper将对象转换成JSON格式字符串 String s = new ObjectMapper().writeValueAsString(book); response.setCharacterEncoding("utf-8"); response.setContentType("application/json"); PrintWriter out = response.getWriter(); out.println(s); out.flush(); out.close(); }直接在控制器方法返回响应的对象
控制器方法的返回类型设置为响应给ajax请求的对象类型
在控制器方法前添加
@ResponseBody
注解,将返回的对象转换成JSON响应给ajax请求如果一个控制器类中的所有方法都是响应ajax请求,则可以直接在控制器类前添加
@ResponseBody
注解@RequestMapping("/update") @ResponseBody public List<Book> update() { System.out.println("---book update"); List<Book> books = new ArrayList<Book>(); books.add(new Book(1,"Java","老张",2.22)); books.add(new Book(2,"C++","老李",3.22)); return books; }控制器响应同步请求的数据传递
对于同步请求的转发响应,我们可以传递参数到转发的页面
返回类型为String:
//1.在控制器方法中定义一个Model类型的参数 //2.在return页面之前,向model中添加键值对,添加的键值对就会被传递到转发的页面 @RequestMapping("/add") public String addBook(String name, String author, double price,Model model){ model.addAttribute("key1","value1"); model.addAttribute("book",new Book(1,"Java","老张",2.22)); return "/tips.jsp"; } //除了使用Model对象传值外,还可以直接使用HttpServletRequest对象 @RequestMapping("/add") public String addBook(String name, String author, double price,HttpServletRequest request){ request.setAttribute("key1","value1"); request.setAttribute("book",new Book(1,"Java","老张",2.22)); return "/tips.jsp"; }返回类型ModelAndView:
@RequestMapping("/add2") public ModelAndView addBook2(String name, String author, double price){ ModelAndView modelAndView = new ModelAndView("/tips.jsp"); modelAndView.addObject("key1","value1"); modelAndView.addObject("book",new Book(1,"Java","老张",2.22)); return modelAndView; }
9.SpringMVC 里面拦截器是怎么写的?
方法一:实现 HandlerInterceptor 接口;
方法二:继承适配器类,接着在接口方法当中,实现处理逻辑,然后在 SpringMVC 的配置文件中配置拦截器即可。
拦截器介绍
SpringMVC提供的拦截器就类似于Servlet-api中的过滤器,可以对控制器的请求进行拦截实现相关的预处理和后处理。
过滤器
是Servlet规范的一部分,所有的web项目都可以使用
过滤器在web.xml配置(可以使用注解),能够拦截所有web请求
拦截器
是SpringMVC框架的实现,只有在SpringMVC框架中才能使用
拦截器在SpringMVC配置文件进行配置,不会拦截SpringMVC放行的资源(jsp\html\css..)
自定义拦截器,创建拦截器
public class MyInterceptor1 implements HandlerInterceptor { //预处理方法 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("--------------预处理"); Enumeration<String> keys = request.getParameterNames(); while (keys.hasMoreElements()){ String key = keys.nextElement(); if("bookId".equals(key)){ return true; } } response.setStatus(400); return false; } //后处理方法 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { modelAndView.addObject("tips","这是通过拦截器的后处理添加的数据"); System.out.println("--------------后处理"); } }配置拦截器
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/book/query"/> <mvc:mapping path="/book/add"/> <mvc:mapping path="/student/**"/> <mvc:exclude-mapping path="/student/add"/> //除了这个之外 <bean class="com.qfedu.utils.MyInterceptor1"/> </mvc:interceptor> </mvc:interceptors>拦截器链
将多个拦截器按照一定的顺序构成一个执行链
![]()