天天看点

springmvc基础整理

springmvc

    • 经典三层架构
    • 入门springmvc
    • 九大组件
    • springmvc 处理流程
    • 数据输出机制
    • 过滤器,监听器,拦截器
    • 处理multipart形式的数据
    • 全局异常处理
    • 请求转发和重定向

经典三层架构

表现层(view 视图+ controller):负责接收请求,转发请求,它转发给业务层

也就是我们常说的web 层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http 协 议请求web 层,web 需要接收 http 请求,完成 http 响应。

业务层:执行业务逻辑,需要操作数据源则使用持久层的功能

持久层:操作数据库

springmvc是一个应用于表现层的框架,是对servlet的封装,简化了servlet的开发

M:(数据模型(各种vo,po,dto)+业务模型(业务逻辑代码))

V:view视图(jsp,html)

C:controller控制器(servlet)

配置<servlet-mappin>的时候注意/ 和/*的区别

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

使用/*会连.jsp请求(跳转jsp)一块拦截(拦截后会在controller中找对应的handler,显然handler中是没有这种xxxx/xx.jsp的url的),/* 的优先级最高。

而使用/不会拦截jsp请求(Tomcat中的servlet会拦截.jsp,并处理)。注意:它不拦截jsp但是它会拦截html,js,css等静态资源

静态资源配置方案

<!--会在springmvc中定义一个DefaultServletHttpRequestHandler对象,
它会对进入dispatcherServlet的url请求进行过滤,如果发现这是静态资源请求,
会把它还给web应用服务器(Tomcat)默认的defaultservlet来处理-->
<mvc:default-servlet-handler>

<!-- 他会把所有满足mapping的请求拦截到 classpath中去-->
<mvc:resources location = "classpath:/" mapping="/resources/**">
           

入门springmvc

新建一个maven项目,配置pom文件

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.1.12.RELEASE</version>
        </dependency>
    </dependencies>
    <!--    需要Tomcat插件可以加入-->
	<build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>8080</port>
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>
    
           

配置web.xml

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--    配置文件的地址,这里让springmvc去加载配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
    </servlet>

<!--    配置拦截路径-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

           

新建配置类springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
    <!--    开启扫描-->
    <context:component-scan base-package="com.test.springmvc.controller"/>
    <!--    配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--        配置视图前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--        配置视图后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
    <!--    自动注册处理器映射器,处理器适配器-->
    <mvc:annotation-driven/>
</beans>
           

新建一个controller

package com.test.springmvc.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.Date;

@Controller
@RequestMapping("/testController")
public class MyController {

    @RequestMapping("/test1")
    public ModelAndView test1() {
        ModelAndView modelAndView = new ModelAndView();
        //向请求域中中添加属性,request.setAttribtue("Date", new Date())
        modelAndView.addObject("date", new Date());
        //加上springmvc.xml设置的视图解析器的前缀和后缀这里相当于
        // modelAndView.setViewName("/WEB-INF/jsp/test.jsp ")
        modelAndView.setViewName("test");
        return modelAndView;
    }
}

           

根据上面controller返回的视图test.jsp新建视图

<%@ page isELIgnored="false" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    test my mvc ${date}
</body>
</html>

           

最后的项目结构是这样的

springmvc基础整理

浏览器输入http://localhost:8080/testController/test1,页面返回

springmvc基础整理

九大组件

HandleMapping:处理器映射器,存储了url请求的路径和handle处理器的映射关系,请求到达后它会去找到对应的handler和interceptor。标注了@RequestMapping的每个方法都可以看成是一个Handler。

HandlerAdapter: 处理器适配器,handler的形式不一样(可能是方法上加注解@requestmapping,或者是类实现了接口,这些都是handler),需要使用不同的适配器来执行handler。

HandlerExceptionResolver:处理handle产生的异常,根据异常设置modelandview。

ViewResolver:视图解析器,拼接视图的前缀和后缀。

RequestToViewNameTranslator:从请求路径中获取viewname,handler没有设置view的时候它从请求中查找视图名。

LocalResolver:国际化处理。用于从请求中解析出 Locale,比如中国 Locale 是 zh-CN,用来表示一个区域。这 个组件也是 i18n 的基础。

ThemeResolver:解析主题,现在很少使用,一般由前端来写页面不使用主题。

MultipartResolver:处理文件上传请求。

FlashMapMavager:重定向的时候进行参数的传递。

springmvc 处理流程

第一步:用户发送请求至前端控制器DispatcherServlet

第二步:DispatcherServlet收到请求调用HandlerMapping处理器映射器

第三步:处理器映射器根据请求Url找到具体的Handler(后端控制器),生成处理器对象及处理器拦截 器(如果 有则生成)一并返回DispatcherServlet

第四步:DispatcherServlet调用HandlerAdapter处理器适配器去调用Handler

第五步:处理器适配器执行Handler

第六步:Handler执行完成给处理器适配器返回ModelAndView

第七步:处理器适配器向前端控制器返回 ModelAndView,ModelAndView 是SpringMVC 框架的一个 底层对 象,包括 Model 和 View

第八步:前端控制器请求视图解析器去进行视图解析,根据逻辑视图名来解析真正的视图。

第九步:视图解析器向前端控制器返回View

第十步:前端控制器进行视图渲染,就是将模型数据(在 ModelAndView 对象中)填充到 request 域

第十一步:前端控制器向用户响应结果

数据输出机制

ModelAndView类中包括ModelMap 和view

直接在controller的方法中声明一个形参ModelMap或者Model,然后使用Model.addObject(“date”, new Date());或者ModelMap.addObject(“date”, new Date());也是可以的。== 甚至直接用Map都可以 ==

===》 运行时ModelMap,Model,Map用的都是BindingAwareModelMap,

BindingAwareMode继承了ExtendedModelMap, 然后ExtendedModelMap继承了ModelMap, 实现了Model接口。

过滤器,监听器,拦截器

过滤器:对请求过滤,作用在servlet之前,对Request请求起到过滤的作用,作用在Servlet之前,如果配置为/*可以对所 有的资源访问(servlet、js/css静态资源等)进行过滤处理

监听器:实现了ServletContextListener接口的服务器端组件,生命周期和web应用一致,只会初始化一次,可以在某些动作前后增加处理。

作用一:做一些初始化工作,web应用中spring容器启动ContextLoaderListener

作用二:监听web中的特定事件,比如HttpSession,ServletRequest的创建和销毁;变量的创建、 销毁和修改等。可以在某些动作前后增加处理,实现监控,比如统计在线人数,利用 HttpSessionLisener等。

拦截器:是SpringMVC、Struts等表现层框架自己的,只会拦截hangder不会拦截jsp、html等。(拦截3次,hander前拦截,hander执行完未跳转页面拦截,跳转后拦截)==》比如实现HanlerInterceptor接口

servlet、filter、listener是配置在web.xml中的(javaee的组件),而intercepor是配置在自己的配置文件中(springmvc等表现层框架的组件)。

public interface HandlerInterceptor {

	default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		return true;
	}

	default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable ModelAndView modelAndView) throws Exception {
	}

	default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable Exception ex) throws Exception {
	}

}
           

单个拦截器的执行流程:

1)程序先执行preHandle()方法,如果该方法的返回值为true,则程序会继续向下执行处理器中的方 法,否则将不再向下执行。

2)在业务处理器(即控制器Controller类)处理完请求后,会执行postHandle()方法,然后会通过 DispatcherServlet向客户端返回响应。

3)在DispatcherServlet处理完请求后,才会执行afterCompletion()方法。

自定义拦截器

public class MyIntercepter01 implements HandlerInterceptor {
/**
* 会在handler方法业务逻辑执行之前执行
* 往往在这里完成权限校验工作 * @param request
* @param response
* @param handler
* @return 返回值boolean代表是否放行,true代表放行,false代表中止 
* @throws Exception
*/
@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
System.out.println("MyIntercepter01 preHandle......");
        return true;
    }
/**
* 会在handler方法业务逻辑执行之后尚未跳转⻚面时执行 
* @param request
* @param response
* @param handler
* @param modelAndView
数据和视图信息进行修改
     * @throws Exception
*/
@Override
    public void postHandle(HttpServletRequest request, HttpServletResponse
response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyIntercepter01 postHandle......"); }
/**
* ⻚面已经跳转渲染完毕之后执行
* @param request
* @param response
* @param handler
* @param ex 可以在这里捕获异常 * @throws Exception
*/
@Override
    public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyIntercepter01 afterCompletion......"); }
}
           

在springmvc.xml注册拦截器

<mvc:interceptors>
   <!--拦截所有handler-->
    <!--<bean class="com.test.interceptor.MyIntercepter01"/>-->
    <mvc:interceptor>
        <!--配置当前拦截器的url拦截规则,**代表当前目录下及其子目录下的所有url-->
        <mvc:mapping path="/**"/>
        <!--exclude-mapping可以在mapping的基础上排除一些url拦截-->
        <!--<mvc:exclude-mapping path="/demo/**"/>-->
        <bean class="com.test.interceptor.MyIntercepter01"/>
    </mvc:interceptor>
</mvc:interceptors>
           

处理multipart形式的数据

上传文件的处理

加入上传文件所需要的jar包

<dependency>
	<groupId>commons-fileupload</groupId> 
	<artifactId>commons-fileupload</artifactId> 
	<version>1.3.1</version>
</dependency>
           

配置上传解析器

<!--配置文件上传解析器,id是固定的multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<!--设置上传大小,单位字节-->
	<property name="maxUploadSize" value="1000000000"/> 
</bean>
           

前端

<%--
1 method="post"
2 enctype="multipart/form-data" 3 type="file"
--%>
<form method="post" enctype="multipart/form-data" action="/demo/upload">
<input type="file" name="uploadFile"/>
<input type="submit" value="上传"/> </form>
           

后台

@RequestMapping("upload")
public String upload(MultipartFile uploadFile, HttpServletRequest request) throws IOException {
	// 文件原名,如xxx.jpg
	String originalFilename = uploadFile.getOriginalFilename(); // 获取文件的扩展名,如jpg
	String extendName =
	originalFilename.substring(originalFilename.lastIndexOf(".") + 1, originalFilename.length());
	String uuid = UUID.randomUUID().toString(); // 新的文件名字
	String newName = uuid + "." + extendName; String realPath =
	request.getSession().getServletContext().getRealPath("/uploads");
	// 解决文件夹存放文件数量限制,按日期存放
	String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); 
	File floder = new File(realPath + "/" + datePath);
	if(!floder.exists()) {
		floder.mkdirs(); 
	}
	uploadFile.transferTo(new File(floder,newName));
	return "success"; 
}
           

全局异常处理

// 可以让我们优雅的捕获所有Controller对象handler方法抛出的异常 
@ControllerAdvice
public class GlobalExceptionResolver {
	@ExceptionHandler(ArithmeticException.class)
	public ModelAndView handleException(ArithmeticException exception,HttpServletResponse response) {
		ModelAndView modelAndView = new ModelAndView(); 
		modelAndView.addObject("msg",exception.getMessage()); 
		modelAndView.setViewName("error");
		return modelAndView;
	} 
}
           

请求转发和重定向

转发:A 找 B 借钱400,B没有钱但是悄悄的找到C借了400块钱给A

url不会变,参数也不会丢失,一个请求

重定向:A 找 B 借钱400,B 说我没有钱,你找别人借去,那么A 又带着400块的借钱需求找到C url会变,参数会丢失需要重新携带参数,两个请求

用flash解决重定向参数丢失,向上下文中添加flash属性,框架会在session中记录该属性值,当 跳转到⻚面之后框架会自动删除flash属性,不需要我们手动删除

@RequestMapping("/handleRedirect")
public String handleRedirect(String name,RedirectAttributes redirectAttributes) {
	//return "redirect:handle01?name=" + name; // 拼接参数安全性、参数⻓度都有局限
	// addFlashAttribute方法设置了一个flash类型属性,该属性会被暂存到session中,在跳转到⻚面之后该属性销毁
	redirectAttributes.addFlashAttribute("name",name); 
	return "redirect:handle01";
}
           

九大组件初始化

// 多部件解析器
@Nullable
private MultipartResolver multipartResolver;
// 区域化 国际化解析器
@Nullable
private LocaleResolver localeResolver;
// 主题解析器
@Nullable
private ThemeResolver themeResolver;
// 处理器映射器组件
@Nullable
private List<HandlerMapping> handlerMappings;
// 处理器适配器组件
@Nullable
private List<HandlerAdapter> handlerAdapters;
// 异常解析器组件
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
// 默认视图名转换器组件
@Nullable
private RequestToViewNameTranslator viewNameTranslator;
// flash属性管理组件
@Nullable
private FlashMapManager flashMapManager;
// 视图解析器
@Nullable
private List<ViewResolver> viewResolvers;
           

在org.springframework.web.servlet.DispatcherServlet#onRefresh方法中初始化

@Override
protected void onRefresh(ApplicationContext context) {
	// 初始化策略
	initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
	// 多文件上传的组件
	initMultipartResolver(context);
	// 初始化本地语言环境
	initLocaleResolver(context);
	// 初始化模板处理器
	initThemeResolver(context);
	// 初始化HandlerMapping
	initHandlerMappings(context);
	// 初始化参数适配器
	initHandlerAdapters(context);
	// 初始化异常拦截器
	initHandlerExceptionResolvers(context);
	// 初始化视图预处理器
	initRequestToViewNameTranslator(context);
	// 初始化视图转换器
	initViewResolvers(context);
	// 初始化 FlashMap 管理器
	initFlashMapManager(context);
}