初识Spring MVC框架

文章目录

  • 前言
  • Spring MVC
    • Spring MVC运行流程
    • 快速开始
    • 请求映射
      • @RequestMapping
      • @RequestParam 请求参数
      • @RequestHeader 请求头
    • 模型数据
      • ModelAndView
      • Map 及 Model
      • @SessionAttributes
      • 字符串
    • 视图和视图解析器
      • 常用的视图实现类
      • 常用的视图解析器实现类
      • 关于重定向和请求转发
    • @ResponseBody
    • 文件上传
    • 拦截器
    • 国际化
      • 本地化解析器和本地化拦截器
    • REST

前言

以下内容是我在学习 Spring MVC 框架时候做的笔记总结。如有错误请指正,谢谢。

Spring MVC

Spring 为展现层提供的基于 MVC 设计理念的优秀的Web 框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。

Spring MVC运行流程

初识Spring MVC框架_第1张图片
(1)用户发送请求至前端控制器DispatcherServlet;
(2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
(3)处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
(4)DispatcherServlet 调用 HandlerAdapter处理器适配器;
(5)HandlerAdapter 经过适配调用具体处理器(Handler,也叫后端控制器);
(6)Handler执行完成返回ModelAndView;
(7)HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
(8)DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
(9)ViewResolver解析后返回具体View;
(10)DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中);
(11)DispatcherServlet响应用户。

快速开始

初识Spring MVC框架_第2张图片
导入相关依赖

<!--Servlet - JSP -->
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
</dependency>
<dependency>
  <groupId>javax.servlet.jsp</groupId>
  <artifactId>jsp-api</artifactId>
  <version>2.2</version>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>

<!--Spring-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.1.9.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jdbc</artifactId>
  <version>5.1.9.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.8.13</version>
</dependency>

在 web.xml 中配置 DispatcherServlet(前端控制器

<!-- 配置DispatcherServlet -->
<servlet>
	<servlet-name>springDispatcherServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<!-- 配置DispatcherServlet 的一个初始化参数:配置SpringMVC配置文件的位置和名称-->
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:springmvc.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>springDispatcherServlet</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

在springmvc.xm中配置自动扫描包以及视图解析器

<!-- 配置自动扫描的包 -->
	<context:component-scan base-package="com.atguigu.springmvc">
 </context:component-scan>
 
 <!-- 配置视图解析器(也可以是html等,支持不同视图类型) -->
 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
     <property name="prefix" value="/WEB-INF/views/"></property>
	 <property name="suffix" value=".jsp"></property>
  </bean>

编写处理请求的处理器HelloWorld.java,并标识为处理器。
使用 @RequestMapping 注解来映射请求的 URL ,返回值会通过视图解析器解析为实际的物理视图, 对于 InternalResourceViewResolver 视图解析器, 会做如下的解析:通过 prefix + returnVal + 后缀 这样的方式得到实际的物理视图,然会做转发操作。

@Controller
public class HelloWorld {
    
	@RequestMapping("/helloworld")
	public String hello() {
		System.out.println("hello world");
		return "success";
	}
}

编写视图
index.jsp

<body>
<a href="helloworld">Hello World</a>
</body>

success.jsp

<body>
	<h1>Sucess Page</h1>
</body>

请求映射

@RequestMapping

Spring MVC 使用 @RequestMapping 注解为控制器指定可以处理哪些 URL 请求,在控制器的类定义及方法定义处都可标注@RequestMapping。DispatcherServlet 截获请求后,就通过控制器上 @RequestMapping 提供的映射信息确定请求所对应的处理方法。

//类定义处:提供初步的请求映射信息
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {
	private static final String SUCCESS = "success";
	
	//方法处:提供进一步的细分映射信息
	@RequestMapping("/testRequestMapping")
	public String testRequestMapping() {
		System.out.println("testRequestMapping");
		return SUCCESS;
	}
}

@RequestMapping 的 value、method、params 及 heads分别表示请求 URL请求方法请求参数请求头的映射条件,他们之间是与的关系,联合使用多个条件可让请求映射更加精确化。

@RequestMapping(value="testMethod",method=RequestMethod.POST)

@RequestMapping(value="testParamsAndHeaders",
		params= {"username","age!=10"},
		headers= {"content=\"text/*"})

@RequestMapping 还支持 Ant 风格的 URL:

  • ?:匹配文件名中的一个字符
  • *:匹配文件名中的任意字符
  • 匹配多层路径
    例如:
    – /user/*/createUser: 匹配/user/aaa/createUser、/user/bbb/createUser 等 URL
    – /user/**/createUser: 匹配/user/createUser、/user/aaa/bbb/createUser 等 URL
    – /user/createUser??: 匹配/user/createUseraa、/user/createUserbb 等 URL

@RequestParam 请求参数

在处理方法入参处使用 @RequestParam 可以把请求参数传递给请求方法。
– value:参数名
– required:是否必须。默认为 true, 表示请求参数中必须包含对应的参数,若不存在,将抛出异常。

@RequestMapping(value="/testRequestParam")
public String testRequestParam(@RequestParam(value="username") String un,
		@RequestParam(value="age",required=false,defaultValue="0") int age) {
	System.out.println("testRequestParam,username="+un+",age="+age);
	return SUCCESS;
}

@RequestHeader 请求头

请求头包含了若干个属性,服务器可据此获知客户端的信息,通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的入参中。

@RequestMapping(value="/testRequestHeader")
	public String testRequestHeader(@RequestHeader(value="Accept-Language") String al) {
		System.out.println("testRequestHeader,Accept-Language:"+al);
		return SUCCESS;
	}

Header中value的参数需在开发者工具栏找
初识Spring MVC框架_第3张图片

模型数据

Spring MVC 提供了以下几种途径输出模型数据:

  • ModelAndView: 处理方法返回值类型为 ModelAndView时, 方法体即可通过该对象添加模型数据
  • Map 及 Model: 入参为org.springframework.ui.Model、org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map中的数据会自动添加到模型中
  • 字符串: 即使只是返回一个字符串,Spring MVC也会自动去找对应的视图,通过 InternalResourceViewResolver 视图解析器去找在配置中定义好的 prefix 前缀 + 字符串 + suffix 后缀的视图。
  • @SessionAttributes: 将模型中的某个属性暂存到HttpSession 中,以便多个请求之间可以共享这个属性
  • @ModelAttribute: 方法入参标注该注解后, 入参的对象就会放到数据模型中

ModelAndView

控制器处理方法的返回值如果为 ModelAndView,则其既包含视图信息,也包含模型数据信息。SpringMVC 会把 ModelAndView 的 model 中数据放入到 request 域对象中。

@RequestMapping("/testModelAndView")
	public ModelAndView testModelAndView() {
		String viewName = SUCCESS;
		ModelAndView modelAndView = new ModelAndView(viewName);
		//添加数据模型到ModelAndView中
		modelAndView.addObject("time", new Date());
		return modelAndView;
	}

index.jsp

<a href="springmvc/testModelAndView">Test ModelAndVies</a>

视图
在这里插入图片描述

Map 及 Model

Spring MVC 在内部使用了一个org.springframework.ui.Model 接口存储模型数据使得目标方法可以添加 Map 类型。举例如下:

@RequestMapping(value = "/getshopbyid",method = RequestMethod.GET)
    @ResponseBody
    private Map<String,Object> getShopById(HttpServletRequest request){
        Map<String,Object> modelMap = new HashMap<String,Object>();
        long shopId = HttpServletRequestUtil.getLong(request, "shopId");
        if(shopId > -1){
            try {
                Shop shop = shopService.getByShopId(shopId);
                List<Area> areaList = areaService.getAreaList();
                modelMap.put("shop",shop);
                modelMap.put("areaList",areaList);
                modelMap.put("success",true);
            }catch (Exception e){
                modelMap.put("success",false);
                modelMap.put("errMsg",e.toString());
            }
        }else {
            modelMap.put("success",false);
            modelMap.put("errMsg","empty shopId");
        }
        return modelMap;
    }

@SessionAttributes

若希望在多个请求之间共用某个模型属性数据,则可以在控制器类上标注一个 @SessionAttributes, Spring MVC将在模型中对应的属性暂存到 HttpSession 中。该注解只能放在类的上面,而不能修饰放方法。
在这里插入图片描述

字符串

prefix 前缀 + 字符串 + suffix 后缀初识Spring MVC框架_第4张图片
请求处理
初识Spring MVC框架_第5张图片
视图
初识Spring MVC框架_第6张图片

视图和视图解析器

视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户。而视图解析器的作用比较单一:将逻辑视图解析为一个具体的视图对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 会在内部将它们装配成一个 ModelAndView 对象,它包含了逻辑名和模型对象的视图。借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP ,也可能是Excel、JFreeChart 等各种表现形式的视图。

 <!-- 配置视图解析器(也可以是html等,支持不同视图类型) -->
 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
     <property name="prefix" value="/WEB-INF/views/"></property>
	 <property name="suffix" value=".jsp"></property>
  </bean>

常用的视图实现类

初识Spring MVC框架_第7张图片

常用的视图解析器实现类

初识Spring MVC框架_第8张图片

关于重定向和请求转发

一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理。如果返回的字符串中带 forward:redirect: 前缀时,Spring MVC 会对他们进行特殊处理:将 forward: 和redirect: 当成指示符,其后的字符串作为 URL 来处理。

  • redirect:/success.jsp:会完成一个到 success.jsp 的重定向的操作
  • forward:/success.jsp:会完成一个到 success.jsp 的转发操作

@ResponseBody

当想把某个控制器的返回转变为JSON数据集的时候只需要在方法上标注@ResponseBody注解即可,而 Sping MVC 是通过 HttpMessageConverter 接口实现。在进入控制器方法前,当遇到标注的 @ResponseBody后,处理器会记录这个方法的响应类型为 JSON 数据集。当执行完执行器后,处理器会启动解析器(ResultResolver)去解析这个结果,它会去轮询注册给 Spring MVC 的 HttpMessageConverter 接口的实现类。因为 MappingJackson2HttpMessageConverter 这个实现类已经被 Spring MVC所注册,加上 Spring MVC将控制器的结果类型标明为 JSON,所以就匹配上了于是通过它在处理器内部把结果转换为了 JSON,并且后续的模型和视图(ModelAndView)就会返回 null,这样视图解析器和视图渲染将不再被执行。(来自《深入浅出Spring Boot 2.x》)
初识Spring MVC框架_第9张图片

文件上传

Spring MVC 为文件上传提供了直接的支持,这种支持是通过即插即用的 MultipartResolver 实现的。下图为实现该接口的两类:在这里插入图片描述
而CommonsMultipartResolver与StandardServletMultipartResolver不同的是前者还需要导入commons-fileupload、commons-io等相关依赖。并且Spring MVC 上下文中默认没有装配 MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用 Spring的文件上传功能,需现在上下文中配置 MultipartResolver。
springmvc.xml

	<!-- 文件上传解析器 -->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="UTF-8"></property>
        <property name="maxUploadSize" value="20971520"></property>
        <property name="maxInMemorySize" value="20971520"></property>
    </bean>

jsp前端页面

<form action="testFileUpload" method="POST" enctype="multipart/form-data">
		File:<input type="file" name="file"/>
		Desc:<input type="text" name="desc"/>
		<input type="submit" value="Submit"/>
	</form>

Controller层

@RequestMapping("/testFileUpload")
	public String testFileUpload(@RequestParam("file") MultipartFile file,
			@RequestParam("desc") String desc) throws IOException {
		System.out.println("OriginalFilename"+file.getOriginalFilename());
		System.out.println("InputStream"+file.getInputStream());
		System.out.println("desc:"+desc);
		return "success";
	}

html前端页面

<li>
	<div class="item-content">
	<div class="item-inner">
	<div class="item-title label">上传文件</div>
		<div class="item-input">
		<input type="file" id="file" >
				</div>
		</div>
		</div>
</li>

Controller层在方法参数中使用MulitpartHttpServletRequest类型或者HttpServletRequest也可以(后面强转即可)

拦截器

当请求来到 DispatcherServet 时,它会根据 HandlerMapping 的机制找到处理器这样就会返回一个 HandlerExecutionChain 对象,这个对象包含处理器和拦截器。这里的拦截器会对处理器进行拦截,这样通过拦截器就可以增强处理器的功能,而所有的拦截器都需要实现 HandIerInterceptor 接口。

public class FirstInterceptor implements HandlerInterceptor{

	/**
	 * 该方法在目标方法之前被调用.
	 * 若返回值为 true, 则继续调用后续的拦截器和目标方法. 
	 * 若返回值为 false, 则不会再调用后续的拦截器和目标方法. 
	 * 
	 * 可以考虑做权限. 日志, 事务等. 
	 */
	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		System.out.println("[FirstInterceptor] preHandle");
		return true;
	}

	/**
	 * 调用目标方法之后, 但渲染视图之前. 
	 * 可以对请求域中的属性或视图做出修改. 
	 */
	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("[FirstInterceptor] postHandle");
	}

	/**
	 * 渲染视图之后被调用. 释放资源
	 */
	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("[FirstInterceptor] afterCompletion");
	}
}

在springmvc.xml中配置拦截器作用路径

<!-- 配置拦截器作用或不作用的路径 -->
	<mvc:interceptor>
		<mvc:mapping path="/emps"/>
		<bean class="com.atguigu.springmvc.interceptors.FirstInterceptor"></bean>
	</mvc:interceptor>

下图为多个拦截器的调用方法顺序(先正序后反序,因为源码中获取拦截器的时候第一个for循环用的是i=0,i++而接下来是i=length,i–):
初识Spring MVC框架_第10张图片

国际化

默认情况下,SpringMVC 根据 Accept-Language 参数判断客户端的本地化类型。

  • 当接受到请求时,SpringMVC 会在上下文中查找一个本地化解析器(LocalResolver),找到后使用它获取请求所对应的本地化类型信息。
  • SpringMVC 还允许装配一个动态更改本地化类型的拦截器,这样通过指定一个请求参数就可以控制单个请求的本地化类型。

本地化解析器和本地化拦截器

  • AcceptHeaderLocaleResolver:根据 HTTP 请求头的Accept-Language 参数确定本地化类型,如果没有显式定义本地化解析器, SpringMVC 使用该解析器
  • CookieLocaleResolver:根据指定的 Cookie 值确定本地化类型
  • SessionLocaleResolver:根据 Session 中特定的属性确定本地化类型
  • LocaleChangeInterceptor:从请求参数中获取本次请求对应的本地化类型

REST

REST:即 Representational State Transfer。(资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

  • 资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的URI就可以,因此 URI 即为每一个资源的独一无二的识别符。
  • 表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
  • 状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源POST 用来新建资源PUT 用来更新资源DELETE 用来删除资源

示例:/order/1

  • HTTP GET :得到 id = 1 的 order
  • HTTP DELETE:删除 id = 1的 order
  • HTTP PUT:更新id = 1的 order
  • HTTP POST:新增 order

而浏览器 form 表单只支持 GET与 POST 请求,而DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使得支持 GET、POST、PUT 与DELETE 请求。
在web.xml文件中配置org.springframework.web.filter.HiddenHttpMethodFilter

<filter>
	<filter-name>HiddenHttpMethodFilter</filter-name>
	<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>HiddenHttpMethodFilter</filter-name>
	<url-pattern>/*

控制层:

@RequestMapping(value = "/testRest/{id}", method = RequestMethod.GET)
public String testRest(@PathVariable Integer id) {
	System.out.println("testRest GET: " + id);
	return SUCCESS;
}

@RequestMapping(value = "/testRest/{id}", method = RequestMethod.DELETE)
public String testRestDelete(@PathVariable Integer id) {
	System.out.println("testRest Delete: " + id);
	return SUCCESS;
}

@RequestMapping(value = "/testRest/{id}", method = RequestMethod.PUT)
public String testRestPut(@PathVariable Integer id) {
	System.out.println("testRest Put: " + id);
	return SUCCESS;
}

@RequestMapping(value = "/testRest", method = RequestMethod.POST)
public String testRest() {
	System.out.println("testRest POST");
	return SUCCESS;
}

你可能感兴趣的:(Spring,java,spring)