JAVA后端面试《Spring MVC》

Spring MVC

    • 1.说一下Spring MVC的执行流程?
    • 2.Spring MVC的核心组件有哪些?
    • 3.什么是Spring MVC?什么是MVC设计模式?
    • 4.Spring MVC的注解有哪些?分别表示什么含义?
    • 5.Spring MVC往页面传值(添加模型数据)的方式有几种?
    • 6.Spring MVC请求转发的写法有几种?
    • 7.Spring MVC 重定向的写法有几种?
    • 8.Spring MVC 常用的JSON解析器有哪些?
    • 9.Spring MVC中怎么解决Http POST请求中文乱码问题?
    • 10.Spring MVC怎么解决响应到页面出现中文乱码?
    • 11.@DateTimeFormat 和 @JsonFormat 注解的区别?
    • 12.Spring MVC如何使用?
    • 13.Spring MVC里的静态资源访问怎么设置?
    • 14.Spring MVC实现文件上传?
    • 15.什么是Lombok?怎么使用?
    • 16.Thymeleaf是什么?怎么使用?
    • 17.Spring MVC中同时存在动态html和jsp,怎么解决视图解析器问题?
    • 18.Spring MVC全局异常处理页面怎么配置?
    • 19.Spring MVC中拦截器的实现过程和拦截顺序?
    • 20.ant风格资源地址支持的3种匹配符分别代表什么意思?
    • 21.Spring MVC怎么实现数据校验?

1.说一下Spring MVC的执行流程?

  • ① 流程图
    JAVA后端面试《Spring MVC》_第1张图片
  • ② 流程分析
    • 1.客户端请求被 DisptacherServlet 接收。
    • 2.根据 HandlerMapping 映射到 Handler。
    • 3.生成 Handler 和 HandlerInterceptor。
    • 4.Handler 和 HandlerInterceptor 以 HandlerExecutionChain 的形式一并返回给 DisptacherServlet。
    • 5.DispatcherServlet 通过 HandlerAdapter 调用 Handler 的方法完成业务逻辑处理。
    • 6.Handler 返回一个 ModelAndView 给 DispatcherServlet。
    • 7.DispatcherServlet 将获取的 ModelAndView 对象传给 ViewResolver 视图解析器,将逻辑视图解析为物理视图 View。
    • 8.ViewResovler 返回一个 View 给 DispatcherServlet。
    • 9.DispatcherServlet 根据 View 进行视图渲染(将模型数据 Model 填充到视图 View 中)。
    • 10.DispatcherServlet 将渲染后的结果响应给客户端。

2.Spring MVC的核心组件有哪些?

  • ① DispatcherServlet:中央调度器,是整个流程控制的核心,控制其他组件的执行,进行统一调度,降低组件之间的耦合性,相当于总指挥。
  • ② Handler:处理器,完成具体的业务逻辑,相当于 Servlet 或 Action。
  • ③ HandlerMapping:处理器映射器,DispatcherServlet 接收到请求之后,通过 HandlerMapping 将不同的请求映射到不同的 Handler。
  • ④ HandlerInterceptor:处理器拦截器,是一个接口,如果需要完成一些拦截处理,可以实现该接口。
  • ⑤ HandlerExecutionChain:处理器执行链,包括两部分内容:Handler 和 HandlerInterceptor(系统会有一个默认的 HandlerInterceptor,如果需要额外设置拦截,可以添加拦截器)。
  • ⑥ HandlerAdapter:处理器适配器,Handler 执行业务方法之前,需要进行一系列的操作,包括表单数据的验证、数据类型的转换、将表单数据封装到 JavaBean 等,这些操作都是由 HandlerApater 来完成,开发者只需将注意力集中业务逻辑的处理上,DispatcherServlet 通过 HandlerAdapter 执行不同的 Handler。
  • ⑦ ModelAndView:装载了模型数据和视图信息,作为 Handler 的处理结果,返回给 DispatcherServlet。
  • ⑧ ViewResolver:视图解析器,DispatcheServlet 通过它将逻辑视图解析为物理视图,最终将渲染结果响应给客户端。

3.什么是Spring MVC?什么是MVC设计模式?

  • Spring MVC: 是目前主流的实现 MVC 设计模式的企业级开发框架,Spring 框架的一个子模块,无需整合,开发起来更加便捷。
  • MVC设计模式: 将应用程序分为 Controller、Model、View 三层,Controller 接收客户端请求,调用 Model 生成业务数据,传递给 View。Spring MVC 就是对这套流程的封装,屏蔽了很多底层代码,开放出接口,让开发者可以更加轻松、便捷地完成基于 MVC 模式的 Web 开发。

4.Spring MVC的注解有哪些?分别表示什么含义?

  • @Controller : 定义在类上,表示将该类交给IOC容器来管理,同时使其成为一个控制器,可以接收客户端请求。
  • @RequestMapping : 该注解将URL请求与业务方法进行映射(一般用来定义请求接口名和请求方式),定义在类上表示父路径名,定义在方法上表示子路径。它有以下六个属性:
    • value: 指定请求的实际地址。
    • method: 指定请求的方式( GET、POST、PUT、DELETE)。
    • consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html。
    • produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回。(如 produces=“application/json” 表示只处理request请求中Accept头中包含了"application/json"的请求)
    • params: 指定request请求中必须包含某些参数值,才让该方法处理请求。(如 params = {"!username",“id=10”} 表示只接收不包含名为username的参数且拥有名为id的参数且参数id值是10的request请求)
    • headers: 指定request请求中必须包含某些指定的header值,才让该方法处理请求。(如headers = “Accept=application/json” 表示请求头中必须有“Accept =application/json”参数才让处理)
  • @RequestParam(value=“paramName”) : 用来获取request请求中名为paramName的参数值,并赋给形参。它有以下三个参数:
    • value: 设置请求参数的名称。
    • required: 默认为true,设置请求中是否必带该参数。
    • defaultValue: 设置默认值,如果请求中没有同名参数时就使用该默认值。
  • @RequestBody: 将前端发来的JSON数据,进行自动解析,并把JSON数据自动封装到形参(形参必须为对象类型)中,且形参对象要与JSON对象的属性一致。
  • @RequestHeader: 获取请求头中的值,并赋值给形参。
@RequestMapping("/request")  
public void query(@RequestHeader("Accept-Encoding") String encoding,  @RequestHeader("Keep-Alive") long keepAlive)  { }  
  • @ResponseBody: 响应体注解,响应信息到前端页面。
    • 注意 :当使用该注解并且方法返回值是对象类型的时候,需要添加jackSON依赖包,将java对象转换为JSON信息再响应到前端。
<dependency>
	<groupId>com.fasterxml.jackson.coregroupId>
	<artifactId>jackson-coreartifactId>
    <version>2.9.6version>
dependency>
<dependency>
    <groupId>com.fasterxml.jackson.coregroupId>
	<artifactId>jackson-databindartifactId>
	<version>2.9.6version>
dependency>
<dependency>
	<groupId>com.fasterxml.jackson.coregroupId>
	<artifactId>jackson-annotationsartifactId>
	<version>2.9.6version>
dependency>
  • @PathVariable: 用来获取URL请求中的一个动态变量值。一般配合RESTful 风格的URL使用。
//URL请求:../rest/zs/10
@RequestMapping("/rest/{name}/{id}")
public String rest(@PathVariable("name") String name, @PathVariable("id") int id){
	System.out.println("name = "+ name + ",id =" + id);//name =zs,id= 10
	return "index";
}
  • @CookieValue(“cookieName”): 获取名为cookieName的cookie的值,并赋值给形参。

@Controller
@RequestMapping("/cookie")
public class HelloController {
 
    @RequestMapping("/show")
    public String test( @CookieValue("JSESSIONID") String jsessionid){
       System.out.println(jsessionid);
        return "hello";
    }
}
  • @ModelAttribute: 用在方法上,使该方法专门用来返回要填充到模型数据中对象,并把模型数据绑定到request域中。这样其它业务方法中无需再处理模型数据,只需要返回视图即可。
@ModelAttribute 
public void getUser(Model model){    
	User user = new User();    
	user.setId(1L);    
	user.setName("李四");    
	model.addAttribute("user",user); 
}

@RequestMapping("/modelAttribute") 
public String modelAttribute(){  
    return "view"; 
}
  • @SessionAttributes:
对于ViewHandler类中所有的业务方法,
只要向request中添加了key="user"、key="address"的对象时,
Spring MVC会自动将该数据添加到session域中,保存的key不变。

@SessionAttributes(value = {"user","address"}) 
public class ViewHandler { }

对于ViewHandler2类中的所有业务方法,
只要向request中添加了数据类型是User和Address对象时,
Spring MVC会自动将该数据添加到session域中,保存的key不变。

@SessionAttributes(types = {User.class,Address.class}) 
public class ViewHandler2 { }

5.Spring MVC往页面传值(添加模型数据)的方式有几种?

  • ① 将模型数据绑定request域
    • HttpServletRequest
    • Map
    • Model
    • ModelMap
    • ModelAndView
    • @ModelAttribute
  • ② 将模型数据绑定到session域
    • HttpSession
    • @SessionAttributes

6.Spring MVC请求转发的写法有几种?

1.不带forward关键字
   默认写法: return "index"; index是逻辑视图名,跳转之前会根据视图解析器的配置进行前缀和后缀的拼接,
   最后跳才转到拼接后的页面. 
2.带forward关键字
   ①物理视图  return "forward:/WEB-INF/jsp/index.jsp";
   ②相对路径  return "forward:second";	 forward后面写 接口名(RequestMapping括号里面的Value值)	 
   ③绝对路径  return "forward:/index/second" :index为类上的接口名,second为类中业务方法的接口名

7.Spring MVC 重定向的写法有几种?

1.相对路径 :return "redirect:second"; second为业务方法中的接口名
2.绝对路径 :return "redirect:/index/second"; index为类上的接口名,second为类中业务方法的接口名
3.特别注意:使用重定向,是不能直接跳转到/WEB-INF/内部的资源的,
	       因为浏览器中不能通过URL地址直接访问/WEB-INF/内部的资源
例: return "redirect:/WEB-INF/jsp/first.jsp"; 这是错误的写法

8.Spring MVC 常用的JSON解析器有哪些?

  • ① jackSON
  • ② fastJSON (阿里巴巴)
  • ③ gSON (谷歌)

9.Spring MVC中怎么解决Http POST请求中文乱码问题?

  • web.xml中添加编码过滤器
<filter>
	<filter-name>encodingFilterfilter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
	<init-param>
	  <param-name>encodingparam-name>
	  <param-value>UTF-8param-value>
	init-param>
filter>
  
<filter-mapping>
	<filter-name>encodingFilterfilter-name>
	
	<url-pattern>/*url-pattern>
filter-mapping>

10.Spring MVC怎么解决响应到页面出现中文乱码?

  • 1.在springmvc.xml文件中配置StringHttpMessageConverter消息转换器
    
	<mvc:annotation-driven>
	    
	    <mvc:message-converters>
	        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
	            <constructor-arg value="UTF-8" />
	        bean>
	    mvc:message-converters>
	mvc:annotation-driven>
  • 2.在类或方法上的@RequestMapping注解中添加produces属性:设置返回的JSON数据的字符编码格式为UTF8
//MediaType为spring的类
@RequestMapping(value = "/rest/{name}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE )  
@ResponseBody  
public User test(@PathVariable("name") String name) {    
   User user = new User();
   user.setName("中文乱码")  
   return user; 
}

11.@DateTimeFormat 和 @JsonFormat 注解的区别?

  • @DateTimeFormat (spring的注解): 入参格式化,把前端提交的时间字符串转换为java.util.Date类型(如果格式匹配的话),不加此注解会抛异常。
  • @JsonFormat(jackson的注解) : 出参格式化,把后端对象的Date类型属性按照指定格式响应到前端。(需要添加jackson依赖)
1.实体类

package com.wpq.domain;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;

@Data
public class DatePojo {
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date date;
}
2.地址栏访问时携带date参数,模拟form表单GET方式提交数据 

http://localhost:8080/date?date=2019-10-12 12:22:22
3.web层接口

@GetMapping("/date")
@ResponseBody
public DatePojo dateTest(DatePojo datePojo){
    System.out.println("datePojo = " + datePojo);
    //控制台打印datePojo = DatePojo(date=Sat Oct 12 12:22:22 CST 2019)
    //证明已经成功封装进去
    return datePojo;
}

4.响应到前端页面的结果
@JsonFormat注解中加timezone = "GMT+8"显示: {"date":"2019-10-12 12:22:22"}
@JsonFormat注解中不加timezone = "GMT+8"显示:{"date":"2019-10-12 04:22:22"}
原因:jackson在序列化时间时是按照国际标准时间GMT进行格式化的,而在国内默认时区使用的是CST时区,两者相差8小时。

12.Spring MVC如何使用?

  • ① 新建Maven工程(选择webapp骨架创建),在项目pom.xml添加Spring-webmvc依赖。
 <dependency>
      <groupId>org.springframeworkgroupId>
	  <artifactId>spring-webmvcartifactId>
	  <version>5.0.11.RELEASEversion>
 dependency>
  • ② 在src/main目录下新建java文件夹和resources文件夹并且右键Mark为相对应的文件类型。
  • ③ 配置 webapp/WEB-INF下的web.xml文件。

<web-app version="2.4"
			 xmlns="http://java.sun.com/xml/ns/j2ee"
			 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
			 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
			 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
			
  
  <welcome-file-list>
	<welcome-file>index.htmlwelcome-file>
	<welcome-file>index.jspwelcome-file>
	<welcome-file>/WEB-INF/jsp/index.jspwelcome-file>
  welcome-file-list>
  
  <servlet>
		<servlet-name>dispatcherServletservlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
		
		<init-param>
		  <param-name>contextConfigLocationparam-name>
		  <param-value>classpath:spring-mvc.xmlparam-value>
		init-param>
		
		
		<load-on-startup>1load-on-startup>
  servlet>
 
  <servlet-mapping>
		<servlet-name>dispatcherServletservlet-name>
		
		<url-pattern>/url-pattern>
  servlet-mapping>

web-app>
  • ④ 在src/main/resources目录下新建spring-mvc.xml文件,并配置。
 
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xmlns:mvc="http://www.springframework.org/schema/mvc"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
	
	
	<context:component-scan base-package="com.wpq"/>
	
	
	<mvc:annotation-driven />
	   
	
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/">property>
		<property name="suffix" value=".jsp">property>
	bean>
beans>

  • ⑤ 创建Handler并使用。
@Controller
public class Hello {
  
   @GetMapping("/hello")
   public String test(){
        return "index";
        //"index":为逻辑视图,视图解析器自动为逻辑视图加上前后缀
        //视图解析器将其解析成/WEB-INF/index.jsp的请求
   }
}

13.Spring MVC里的静态资源访问怎么设置?

  • 方式一:在spring-mvc.xml文件中配置静态文件的存放位置
   
 <mvc:resources mapping="/static/**" location="/static/"/>

 1.location元素:表示webapp目录下的static包下的所有文件;
 2.mapping元素:表示以/static开头的所有请求路径,如/static/a 或者/static/a/b;
 3.作用:DispatcherServlet不会拦截以/static开头的所有请求路径,并当作静态资源交由Servlet处理。
	    比如设置之后DispatcherServlet就不会拦截src的请求了,这样就可以拿到jquery-3.2.1.min.js这个包了 
	    <script src="/static/js/jquery-3.2.1.min.js" type="text/javascript">script>

  • 方式二:在spring-mvc.xml中配置default-servlet-handler处理静态资源的访问,配合mvc注解驱动使用,注意要放在mvc注解驱动的下面。

<mvc:annotation-driven />


<mvc:default-servlet-handler/>

14.Spring MVC实现文件上传?

  • ① 前端页面表单设置enctype属性。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件上传title>
head>
<body>
    <%--注意:文件上传表单中,必须添加enctype="multipart/form-data"--%>
    <form method="post" action="upload" enctype="multipart/form-data">
        <input type="file" name="file"/><br/>
        <input type="submit" value="上传"/>
    form>
body>
html>
  • ② 在spring-mvc.xml文件中配置CommonsMultipartResolver通用多媒体文件解析器。

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.wpq.mvc.web,com.wpq.mvc.exception"/>

    <mvc:annotation-driven/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    bean>

    
    
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="UTF-8"/>
        
        <property name="maxUploadSize" value="5242880"/>
        
        <property name="uploadTempDir" value="file:d:/upload/"/>
    bean>

beans>
  • ③ 新建UploadController,里面写个方法专门处理上传过来的文件,使用MultipartFile类型接收上传过来的文件。
package com.wpq.mvc.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;

@Controller
public class UploadController {

    @ResponseBody
    @PostMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile file) throws IOException {
        if (!file.isEmpty()) {
            //获取文件名称
            String filename = file.getOriginalFilename();
            //拼接到指定路径名下
            File destFile = new File("d:/upload/" + filename);
            if (!destFile.exists()) {
                 //如果目录不存在,就创建一个
                 destFile.mkdirs();
            }
            //把内存中的文件,输出到某个目的地,从而实现文件的持久化
            file.transferTo(destFile);
        }

        return "ok";
    }

}

15.什么是Lombok?怎么使用?

  • 概念: Lombok能通过注解的方式,在编译时自动为类生成构造器、getter/setter、equals、hashcode、toString方法。出现的神奇就是在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。
  • 使用过程
 1.在idea中下载lombok插件
 2.在项目pom.xml中添加lombok依赖
	<dependency>
		<groupId>org.projectlombokgroupId>
		<artifactId>lombokartifactId>
		<version>1.16.22version>
	dependency> 			
3.在实体类中使用Lombok相关注解
        @Data
		@Setter
		@Getter
		@AllArgsConstructor
		@NoArgsConstructor
		@RequiredArgsConstructor
		@Log4j
		@Slf4j
		@EqualsAndHashCode
		@ToString

16.Thymeleaf是什么?怎么使用?

  • 概念: 是一种静态页面模板,可以实现在html页面中动态加载数据,使html成为动态网页。
  • 使用步骤
    • ① 添加thymeleaf依赖
<dependency>
    <groupId>org.thymeleafgroupId>
	<artifactId>thymeleafartifactId>
	<version>3.0.11.RELEASEversion>
dependency>
<dependency>
	<groupId>org.thymeleafgroupId>
	<artifactId>thymeleaf-spring5artifactId>
	<version>3.0.11.RELEASEversion>
dependency>
  • ② spring-mvc.xml文件中配置thymeleaf的解析器。

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.wpq.web"/>

    <mvc:annotation-driven/>
     
	<bean id="templateResolver" class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
		<property name="prefix" value="/html/"/>
		<property name="suffix" value=".html"/>
		<property name="characterEncoding" value="UTF-8"/>
		<property name="templateMode" value="HTML5"/>
		
		<property name="cacheable" value="false"/>
	bean>

	
	<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
		<property name="templateResolver" ref="templateResolver"/>
	bean>

	
	<bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
		<property name="characterEncoding" value="UTF-8"/>
		<property name="templateEngine" ref="templateEngine"/>
	bean>    
beans>
  • ③ 新建html,添加Thymeleaf的命名空间。
<html lang="en" xmlns:th="http://www.thymeleaf.org">
			<table>
			   <thead>
			   <td>用户名td>
			   <td>年龄td>
			   thead>
			   <tr th:each="user:${users}" >
				   <td th:text="${user.id}">td>
				   <td th:text="${user.name}">td>
			   tr>
			table>
html>
  • ④ 后端编写对应接口,带着数据跳转到Thymeleaf页面,html就能拿到数据。

17.Spring MVC中同时存在动态html和jsp,怎么解决视图解析器问题?

  • ① 在spring-mvc.xml文件中添加 ContentNegotiatingViewResolver内容协调视图解析器,把SpringMVC默认视图解析器和Thymeleaf的视图解析器内嵌进去。
  • ② 在两种视图解析器中分别设置viewNames属性:把jsp(文件夹名)或者html(文件夹名)抽取出来放在Value里面做前缀,得以区分两种视图解析器。

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.wpq.web"/>
    <mvc:annotation-driven/>
    
	<bean id="templateResolver" class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
		<property name="prefix" value="/html/"/>
		<property name="suffix" value=".html"/>
		<property name="characterEncoding" value="UTF-8"/>
		<property name="templateMode" value="HTML5"/>
		
		<property name="cacheable" value="false"/>
	bean>

	
	<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
		<property name="templateResolver" ref="templateResolver"/>
	bean>
    
	<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
		<property name="viewResolvers">
			<list>
				
				<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
					
					<property name="prefix" value="/WEB-INF/"/>
					<property name="viewNames" value="jsp/*"/>
					<property name="suffix" value=".jsp"/>
					
					<property name="order" value="1"/>
				bean>

				
				<bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
					<property name="characterEncoding" value="UTF-8"/>
					<property name="templateEngine" ref="templateEngine"/>
					
					<property name="viewNames" value="html/*"/>
					<property name="order" value="2"/>
				bean>
			list>
		property>
	bean>

beans>
  • ③ 最后在接口代码中,明确指明使用的是哪种视图解析器 如 return “jsp/1” 或者 return “html/2” ,这样就解决了两种视图解析器不能共存的问题。

18.Spring MVC全局异常处理页面怎么配置?

  • 方式一: 在web.xml文件中进行错误页面的配置

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
    <servlet>
        <servlet-name>SpringMVCservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>classpath:spring_mvc.xmlparam-value>
        init-param>
        
        <init-param>
            <param-name>throwExceptionIfNoHandlerFoundparam-name>
            <param-value>trueparam-value>
        init-param>
        <load-on-startup>1load-on-startup>
    servlet>

    <servlet-mapping>
        <servlet-name>SpringMVCservlet-name>
        <url-pattern>/url-pattern>
    servlet-mapping>
    
    
    <error-page>
	    <error-code>404error-code>
	    <location>/WEB-INF/jsp/404.jsplocation>
    error-page>

    <error-page>
	    <error-code>500error-code>
	    <location>/WEB-INF/jsp/500.jsplocation>
    error-page>
web-app>
  • 方式二: 新建一个全局异常处理类,在类上加上@ControllerAdvice注解,保证spring-mvc.xml中的组件扫描器可以扫描到此包。
package com.wpq.mvc.exception;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;

/**
 * ControllerAdvice:增强版的controller
 * 注意:配置该类所在包的扫描范围.
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    //Exception:可以处理大多数异常,基本上所有的500异常都可以处理,但是404异常不能处理
    //处理所有的500异常
    //@ExceptionHandler(value = IllegalArgumentException.class)
    @ExceptionHandler(value = Exception.class)
    public ModelAndView handleException(Exception ex) {
        //常规的处理策略:
        //1.在这里进行异常的捕获或者抛出;
        //2.在这里进行统一的异常记录,都需要把异常信息记录在一个日志文件中,或者利用ELK技术进行异常信息的采集;
        // log.warn(ex.getMessage());
        //3.直接把异常信息简单封装处理一下,把异常信息告诉给前端,让前端负责错误页面的展示.
        //window.location=500.html

        ///WEB-INF/jsp/500.jsp
        //return "500";

        ModelAndView mv = new ModelAndView();
        mv.addObject("msg", ex.getMessage());
        ///WEB-INF/jsp/500.jsp
        mv.setViewName("500");
        return mv;
    }

    //404异常比较特殊:只单独编写异常处理方法,不能实现404跳转
    //用来处理404异常
    @ExceptionHandler(NoHandlerFoundException.class)
    public String handle404Exception(NoHandlerFoundException ex, Model model) {
        model.addAttribute("msg", ex.getMessage());
        return "404";
    }

}

19.Spring MVC中拦截器的实现过程和拦截顺序?

  • ① 新建拦截器类MyInterceptor01和MyInterceptor02,让它们都实现HandlerInterceptor接口,重写preHandle,postHandle和afterCompletion方法(也可以只创建一个拦截器类),打印语句中数字代表了拦截器的执行顺序。
package com.wpq.mvc.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 创建SpringMVC中的拦截器
 */
public class MyInterceptor01 implements HandlerInterceptor {

    /**
     * 执行时机:在我们编写的处理器(控制器)工作之前执行xxx任务.
     * 使用场景:一般进行用户身份校验,看用户是否具有某些权限.
     * 方法返回值:
     * true:不进行拦截,执行完该拦截器的工作之后,会进入到下一个拦截器或者处理器;
     * false:进行拦截,不放行,后面的拦截器或者处理器都不能工作了.
     * 执行顺序:首先执行该方法,该方法的执行顺序与注册顺序正相关,注册的早,就执行的早!
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("1.MyInterceptor01--->preHandle()方法执行了...");
        return true;
    }

    /**
     * modelAndView:来自于处理器适配器从Handler身上解析出来的对象.
     * 执行时机:是在处理器适配器已经处理完我们自己编写的处理器/控制器之后,返回ModelAndView之前工作的.
     * 使用场景:一般是对ModelAndView进行进一步的统一的修改/处理.
     * 执行顺序:执行顺序与注册顺序逆相关,注册的越早,执行的越晚!
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        System.out.println("5.MyInterceptor01--->postHandle()方法执行了...");
    }

    /**
     * 执行时机: 当ModelAndView成功的送达DispatcherServlet后,开始执行该方法.
     * 使用场景:一般在该方法中对整个请求过程中产生的异常信息进行整理收集,或者进行日志的采集.
     * 执行顺序:执行顺序与注册顺序逆相关,注册的越早,执行的越晚!
     * 注意:afterCompletion方法的执行与否,取决于preHandle()是否成功的执行,且返回值为true!
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("7.MyInterceptor01--->afterCompletion()方法执行了...");
    }

}

package com.wpq.mvc.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 创建SpringMVC中的拦截器
 */
public class MyInterceptor02 implements HandlerInterceptor {

    /**
     * 执行时机:在我们编写的处理器(控制器)工作之前执行xxx任务.
     * 使用场景:一般进行用户身份校验,看用户是否具有某些权限.
     * 方法返回值:
     * true:不进行拦截,执行完该拦截器的工作之后,会进入到下一个拦截器或者处理器;
     * false:进行拦截,不放行,后面的拦截器或者处理器都不能工作了.
     * 执行顺序:首先执行该方法...
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("2.MyInterceptor02--->preHandle()方法执行了...");
        return true;
    }

    /**
     * modelAndView:来自于处理器适配器从Handler身上解析出来的对象.
     * 执行时机:是在处理器适配器已经处理完我们自己编写的处理器/控制器之后,返回ModelAndView之前工作的.
     * 使用场景:一般是对ModelAndView进行进一步的统一的修改/处理.
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        System.out.println("4.MyInterceptor02--->postHandle()方法执行了...");
    }

    /**
     * 执行时机: 当ModelAndView成功的送达DispatcherServlet后,开始执行该方法.
     * 使用场景:一般在该方法中对整个请求过程中产生的异常信息进行整理收集,或者进行日志的采集.
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("6.MyInterceptor02--->afterCompletion()方法执行了...");
    }

}

package com.wpq.mvc.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * 我们自己创建的一个处理器.
 */
@Controller
public class IndexController {

    @RequestMapping(value = "/index", method = RequestMethod.GET)
    public String show() {

        System.out.println("3.Controller被执行了...");

        return "index";
    }

}

  • ② spring-mvc.xml文件中注册拦截器。

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.wpq.mvc.web"/>                            
    <mvc:annotation-driven/>

    
    <mvc:interceptors>
        <mvc:interceptor>
            
            <mvc:mapping path="/**"/>
            <bean class="com.wpq.mvc.interceptor.MyInterceptor01"/>
        mvc:interceptor>

        <mvc:interceptor>
            
            <mvc:mapping path="/**"/>
            <bean class="com.wpq.mvc.interceptor.MyInterceptor02"/>
        mvc:interceptor>
    mvc:interceptors>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    bean>

beans>

JAVA后端面试《Spring MVC》_第2张图片

20.ant风格资源地址支持的3种匹配符分别代表什么意思?

	1 ?  :匹配文件名中的一个字符
	2 *  :匹配文件名中的任意多个字符
	3 ** :匹配多层路径	

	   @RequestMapping("/ant/**/test")
	   public String ant(){
	       return "success";
	   }

21.Spring MVC怎么实现数据校验?

  • Spring MVC 提供了两种数据校验的方式:1、基于 Validator 接口。2、使用 Annotation JSR - 303 标准进行校验,实际开发选择第二种方式。
  • ① 使用 Annotation JSR - 303 标准进行验证,需要导入支持这种标准的依赖 jar 文件,这里我们使用 Hibernate Validator。

<dependency>
  <groupId>org.hibernategroupId>
  <artifactId>hibernate-validatorartifactId>
  <version>5.3.6.Finalversion>
dependency>

<dependency>
  <groupId>javax.validationgroupId>
  <artifactId>validation-apiartifactId>
  <version>2.0.1.Finalversion>
dependency>

<dependency>
  <groupId>org.jboss.logginggroupId>
  <artifactId>jboss-loggingartifactId>
  <version>3.3.2.Finalversion>
dependency>
  • ② 通过注解的方式直接在实体类中添加相关的验证规则。
package com.boot.pojo;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.persistence.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;

@Data
@Table(name = "tb_spu")
@ApiModel(value = "Spu实体对象")
public class Spu {
    @Id //绑定数据库表主键id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//主键由数据库表自动生成
    //@NotNull(message = "id不能为空")
    @ApiModelProperty(value = "Spu的id")
    private Integer id;

    @ApiModelProperty(value = "主题")
    @NotEmpty(message = "title不能为null或长度为0")
    private String title;

    @ApiModelProperty(value = "sub主题")
    @Length(min = 1,
            max = 255,message = "标题长度不能大于255且不能小于1")
    @NotNull(message = "标题不能为空")
    private String subTitle;

    @NotNull(message = "cid不能为空")
    private Integer cid1;
    private Integer cid2;
    private Integer cid3;
    private Integer brandId;
    @ApiModelProperty(value = "上下架")
    private Boolean saleable;
    private Integer valid;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")//出参
    //@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") //入参
    @ApiModelProperty(hidden = true)
    private Date createTime;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty(hidden = true)
    private Date lastUpdateTime;

    /**
     * 以下为新增的字段,非spu表内字段
     */
    @Transient//忽略实体映射数据库表
    private String bname;
    @Transient
    private String cname;

}

  • ③ Controller层接口形参中使用@Valid注解开启验证,配合BindingResult 使用,BindingResult用于获取验证结果。
 @ResponseBody
 @PostMapping("/date")
 @ApiOperation(value = "测试接口",response = Spu.class,httpMethod = "POST")
 public Object date(@Valid @RequestBody Spu spu , BindingResult br){
     Map<String,Object> errorMap = new HashMap<>();
     StringBuffer sb = new StringBuffer();
    if (br.hasErrors()){
         List<FieldError> errors = br.getFieldErrors();
         for (FieldError error : errors) {
             sb.append(error.getDefaultMessage()+";");
         }
         errorMap.put("error",sb);
         return errorMap;
     }
     System.out.println("spu = " + spu);
     return spu;
 }
  • ④ spring-mvc.xml中开启mvc注解驱动。
     <mvc:annotation-driven />
  • ⑤ POSTMAN中发送JSON数据到接口进行测试。
    JAVA后端面试《Spring MVC》_第3张图片
  • Hibernate Validate 常用注解
注解 描述
@Null 必须为null
@NotNull 不能为null
@AssertTrue 必须为true
@AssertFalse 必须为false
@Min 必须为数字,其值大于或等于指定的最小值
@Max 必须为数字,其值小于或等于指定的最大值
@DecimalMin 必须为数字,其值大于或等于指定的最小值
@DecimalMax 必须为数字,其值小于或等于指定的最大值
@Size 集合的长度
@Digits 必须为数字,其值必须再可接受的范围内
@Past 必须是过去的日期
@Future 必须是将来的日期
@Pattern 必须符合正则表达式
@Email 必须是邮箱格式
@Length 长度范围
@NotEmpty 不能为null,长度大于0
@Range 元素的大小范围
@NotBlank 不能为null,字符串长度大于0(限字符串)

你可能感兴趣的:(JAVA后端面试)