springmvc工作流程_SpringMVC概述和基础知识详解

一. SpringMVC概述及原理

1. SpringMVC是什么

Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),[Struts 2](https://baike.baidu.com/item/Struts 2/2187934)(一般老项目使用)等。

SpringMVC 已经成为目前最主流的 MVC 框架之一, 从 Spring3.0 的发布, 就已全面超越 Struts2,成为最优秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful 编程风格的请求。

2. MVC和三层架构

MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。


控制器(Controller):Servlet,控制器主要处理用户的请求

视图(View):HTML, JSP, 前端框架

模型(Model):逻辑业务程序(后台的功能程序), Service, Dao, JavaBean

JavaWEB发展史

Model1

所有的业务逻辑交给jsp单独处理完成,一个web项目只存在DB层和JSP层,所有的东西都耦合在一起,对后期的维护和扩展极为不利。

a2cf6c0eb7c94f5abeafcf3375f07e6b

Model2 第一代

JSP Model2有所改进,把业务逻辑的内容放到了JavaBean中,而JSP页面负责显示以及请求调度的工作。虽然第二代比第一代好了些,但JSP还是把view和controller的业务耦合在一起。依然很不理想。

5b37249c07e9437a963a7ce3fbcabcc3

Model2 第二代(三层架构)

Model2第二代就是现在大力推广的和使用的mvc,将一个项目划分为三个模块,各司其事互不干扰,既解决了jsp所形成的耦合性,又增加了逻辑性、业务性以及复用性和维护性

表示层(web层):包含JSP,Servlet等web相关的内容

业务逻辑层(Service):处理业务,不允许出现servlet中的request、response。

数据层(Data Access Object):也叫持久层,封装了对数据库的访问细节。

其中 web层相当于mvc中的view+controller,Service层和dao层相当于mvc中的model。

73df039c65284b2db8da0a779f089afa

3. SpringMVC 在三层架构的位置

MVC模式:(Model-View-Controller):为了解决页面代码和后台代码的分离.

3d3dae10db25451889e959f075305b36

二. 入门示例

1. 配置流程-基于XML的配置

1.1.搭建普通Maven项目

12638012693f451c8b00e5743c3297a3
1c7e6e9209f74b818158f68afcd6c58e
5056ba368eb0464ba11e05978c875d04

使用插件将项目转换为web项目

335f250b9fb94085a2167efea69b9c54

转换成功:

f77536d1429649389de2324f12b444f6

查看是否生成webapp目录和maven项目打包方式是否变为war

34aea8c7b4ac41fd9fc648b2e43d67b5

添加SpringMVC依赖

org.springframework    spring-webmvc    5.0.6.RELEASE

查看关系依赖图

84cb7bcc3dd445d0a5f7a089671ed6ce

1.2.在web.xml配置核心控制器

<?xml version="1.0" encoding="UTF-8"?>dispatcherorg.springframework.web.servlet.DispatcherServletdispatcher*.form

1.3.创建一个Spring的配置文件

<?xml version="1.0" encoding="UTF-8"?>

mvc:annotation-driven 说明

在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。

在springmvc早期版本中需要我们自己加载springmvc的三大组件(现在我们使用的版本5.0.6会自动加载这三大组件)

**处理器映射器:RequestMappingHandlerMapping **

处理器适配器:RequestMappingHandlerAdapter

处理器解析器:ExceptionHandlerExceptionResolver

在早期的版本中使用 自动加载这三大组件,但是高版本的不需要来加载

同时它还提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB,读写JSON的支持(Jackson)。我们处理响应ajax请求时,就使用到了对json的支持(配置之后,在加入了jackson的core和mapper包之后,不写配置文件也能自动转换成json)

springmvc配置文件说明

注意:默认的Spring配置文件放在WEB-INF下,名为{servlet-name}-servlet.xml

{servlet-name}指的是,核心控制器配置的名字

如:dispatcherServlet-servlet.xml

当请求被springmvc处理时,springmvc会去默认路径下加载xxxx-servlet.xml核心配置文件

e8b3e2a5d3b64ef3a9378c3c065af431

但是我们在开发中一般都是把配置文件写在classes下的,我们可以在web.xml中设置springmvc配置文件的路径

dispatcherorg.springframework.web.servlet.DispatcherServletcontextConfigLocationclasspath:dispatcher-servlet.xmldispatcher*.form

1.4.创建一个业务控制器

package com.dfbz.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.servlet.ModelAndView;@Controllerpublic class HelloController{    //代表此方法的访问路径为/hello.form    @RequestMapping("/hello.form")    public ModelAndView hello(){                ModelAndView mav=new ModelAndView();        mav.addObject("msg","小标");        mav.setViewName("/hello.jsp");        return mav;    }}

1.5.创建一个返回的视图页面

   Title   ${msg },欢迎您!

1.7. SpringMVC的工作流程

9cf1e1090ad641558db79a2fdb890e42

1、客户端发送请求给前端控制器(DispatcherServlet)

2、dispatcherServlet接收到请求调用HandlerMapping处理器映射器

3、处理器映射器根据请求的url找对应的处理器,生成处理器对象(handler)返回

4、dispatchServlet将handler传入处理器适配器执行

5、处理器适配器执行handler

6、执行完成最终封装一个ModelAndView

7、将ModelAndView返回给前端控制器

8、前端控制器将请求的路径交给视图解析器进行解析

9、最终封装一个View对象给dispatcherServlet,此View对象封装了响应参数

10、JSP页面渲染数据

11、响应客户端

1.8 SpringMVC源码分析

我们知道SpringMVC实质上是对servlet进行封装,让我们的开发更加简便

1. 准备工作

我们知道springmvc在工作开始之前会加载默认的处理器映射器、处理器适配器、处理器解析器等

可以在spring-webmvc-5.0.6.RELEASE.jar源码包下查看DispatcherServlet.properties文件看有哪些处理器是springmvc默认加载的

dd518495444e4b089ec48dd6168a3aab
90813c7809f348ccab5d8ebb7a6a92e5

2. 查看DispatcherServlet的继承体系:

58324593e3264a598cd56e66955adb89

我们发现DispatcherServlet最终还是继承与HttpServlet,那么我们就直接找service方法吧!

经打断点发现,最终会走向DispacherServlet的doDispacher方法!

cd026700dcc64d269d19eab5f32a7132

此时请求进入DispatcherServlet,按照我们画图分析的结果应该是把请求交给处理器映射器HandlerMapping最终返回一个Handler

3. 查看HandlerMapping接口:

305d8f3eb2484f9bbe061ca3f9d0fa28

4. 寻找HandlerMapping实现类:

59e4f26fe7b043a98c48d93b6437d1dd
02d8171c395442f1bd32a6c390c3254a

接下来进入处理器适配器HandlerAdapter执行handler最终返回一个ModelAndView

5. 查看HandlerAdapter接口:

a99737fdcce24d3189ede48ad12a4702

6. 查看HandlerAdapter实现类:

143c05efbdbd4e0ebcfa57dbf9ba2334
cec16c2e4884446d90ab744c3bdd3953

然后请求交给视图解析器进行解析最终返回一个View对象

7. 查看View接口:

3b575537222a4394b056601d8db34611

8. 查看View实现类:

12ba412c11f04cff9c3edf2c078459e0
15e0bf72eb8b43d1a91b34b8e53648b7

9. 查看View信息:

ca1da6f749634c81b9775e9d1332179e

1.9.核心控制器

SpringMVC自带了拦截器请求的核心控制器.所以就可以在请求过来的时候,直接启动Spring框架

默认情况下,Spring容器是在核心控制器DispatcherServlet获得请求后才启动的.

能不能网站启动的时候,Spring容器就立刻启动.

dispatcherorg.springframework.web.servlet.DispatcherServlet1

三. Controller方法返回值

返回值


返回String

可以返回视图字符串,解析器会自动解析

@RequestMapping("/demo3_1")public String demo3_1(){    return "/success.jsp";           //直接返回字符串}

返回ModelAndView

ModelAndView是SpringMVC帮我们提供的,即"模型和视图"

@RequestMapping("/demo3_2")public ModelAndView demo3_2(){          //返回ModelAndView    ModelAndView mav=new ModelAndView();    mav.setViewName("success.jsp");    mav.addObject("username","东方标准");    return mav;}

返回void

一般用于使用原生的Servlet对象或者ajax请求

@RequestMapping("/demo3_3")//返回void(一般用于ajax)public void demo3_2(HttpServletResponse response) throws IOException {              response.setContentType("text/html;charset=utf8");    response.getWriter().write("东方标准");}

转发和重定向


SpringMVC提供了一个 String 类型返回值之后会自动解析forward、redirect等特殊字符串

视图解析器配置的前缀和后缀解析不支持forward、redirect

:forward:代表转发request.getRequestDispatcher(url).forward(request,response)

:redirect:代表重定向response.sendRedirect(url)

@RequestMapping("/demo3_4")public String demo3_4(Model model)  {          //转发    System.out.println("执行啦!");    model.addAttribute("username","东方标准");    return "forward:/success.jsp";}
@RequestMapping("/demo3_5")public String demo3_5(HttpSession session)  {          //重定向    session.setAttribute("password","admin");    System.out.println("执行啦!");    return "redirect:/success.jsp";}

四. 映射路径-@RequestMapping

1. 探究RequestMapping

注解式处理器映射器,对类中标记了@ResquestMapping的方法进行映射。根据@ResquestMapping定义的url匹配@ResquestMapping标记的方法,匹配成功返回HandlerMethod对象给前端控制器。HandlerMethod对象中封装url对应的方法Method。

@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Mappingpublic @interface RequestMapping {}

命名空间

按照我们传统的url写法不能很好的规定请求路径,即不能按照业务来区分请求

例如现在user需要定义一个findById,goods也需要定义一个findById,此时就会有冲突,针对这种现象我们可以在类上定义一个命名空间,即在类上使用@RequestMapping注解,类似于一级目录,以后访问此类下的任意资源都需要加上此目录

类上

请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。 写的话需要以/开头。它出现的目的是为了使我们的 URL 可以按照模块化管理:

例如:

user模块:

/user/register

/user/update

/user/findById

goods模块:

/goods/add

/goods/update

/goods/findById

映射路径的有三种:标准的映射路径,带通配符的映射路径,带路径变量的映射路径

方法上

请求 URL 的第二级访问目录。

属性:

  • value:用于指定请求的 URL。 它和 path 属性的作用是一样的。
  • method:用于指定请求的方式。
  • params:用于指定限制请求参数的条件。 它支持简单的表达式。 要求请求参数的 key 和 value 必须和配置的一模一样。

params = {“userId”},表示请求参数必须有 userId,区分大小写

params = {“userId!=20”},表示请求参数中 id不能是 20。可以不携带userId参数,区分大小写

headers:用于指定限制请求消息头的条件。

package com.dfbz.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.servlet.ModelAndView;@Controllerpublic class HelloController{    public HelloController(){        System.out.println("Hello创建了");    }    /*    代表此方法的访问路径为/hello.form,如果携带userId参数那么参数必须不能等于1    并且提交方式一定要为POST    */    @RequestMapping(value = "/hello.form",params = "userId!=1",method = RequestMethod.POST)    public ModelAndView hello(){        ModelAndView mav=new ModelAndView();        mav.addObject("msg","小标");        mav.setViewName("/hello.jsp");        return mav;    }}

小结:

1.参数必须包括:params={“username”,“password”}

2.参数不能包括:params={"!userid"}

3参数值必须是指定的值:params={“username=zhangsan”})

4.参数值必须不是指定的值:params={“userid!=123”})

2.3. RESTFUL

所谓的路径变量,就是将参数放在路径里面,而不是放在?的后面

如:原get请求方法 /login.mvc?username=’zhangsan’&pwd=’123456’

路径变量写法:

/zhangsan/123456/login.form

2.3.1 什么是RESTFUL

REST(英文:Representational State Transfer,简称REST)RESTful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

2.3.2 RESTFUL示例:

0415b3738b214765bb00bd2ad9a43323

请求方式有几种?7种

e3597df81b1145ee839e319fa11b606a

jsp、html,只支持get、post。

基于restful风格的url:

添加

http://localhost:8080/SpringMVC_01/user

提交方式: post

修改

http://localhost:8080/SpringMVC_01/user

提交方式:put

删除

http://localhost:8080/SpringMVC_01/user/101

提交方式:delete

查询

http://localhost:8080/SpringMVC_01/user/102

提交方式:get

五. 数据绑定

1. 数据绑定是什么

SpringMVC里面,所谓的数据绑定就是将请求带过来的表单数据绑定到执行方法的参数变量中,或将服务器数据绑定到内置对象,传递到页面

2. 自动绑定的数据类型

2.1 自动绑定数据类型

  • 基本数据类型:基本数据类型+String+包装类
  • 包装数据类型(POJO):包装实体类
  • 数组和集合类型:List、Map、Set、数组等数据类型

2.2 内置绑定数据自动绑定:

ServletAPI:

HttpServletRequest

HttpServletResponse

HttpSession

SpringMVC内置对象

Model

ModelMap

ModelAndView

Model和ModelMap默认都是存储了Request请求作用域的数据的对象

这个两个对象的作用是一样.就将数据返回到页面.

测试页面:

    Title

测试ServletAPI绑定

测试参数类型绑定

属性参数绑定

测试对象参数绑定

测试数组类型绑定

测试Pojo对象数据绑定

Pojo封装数组

Pojo封装user

Pojo封装list

Pojo封装map

测试Controller:

package com.dfbz.controller;import com.dfbz.entity.Pojo;import com.dfbz.entity.User;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import java.util.Arrays;import java.util.List;@Controllerpublic class DemoController {    @RequestMapping("/demo1")            //自定义属性绑定    public String demo1(HttpServletRequest request, HttpServletResponse response, HttpSession session){        request.setAttribute("username","zhangsan");        return "/success.jsp";    }    @RequestMapping("/demo2")            //属性参数绑定    public String demo2(String username){        System.out.println(username);        return "/success.jsp";    }    @RequestMapping("/demo3")            //对象参数绑定    public String demo3(User user){        System.out.println(user);        return "/success.jsp";    }    @RequestMapping("/demo4")            //数组参数绑定    public String demo4(String[] ids){        System.out.println(Arrays.toString(ids));        return "/success.jsp";    }    @RequestMapping("/demo5")            //Pojo对象参数绑定    public String demo5(Pojo pojo){        System.out.println(pojo);        return "/success.jsp";    }}

3. Post提交方式乱码解决

测试GET/POST提交中文数据

页面:

测试Post乱码

controller:

@RequestMapping("/demo7.form")            //Pojo对象参数绑定public String demo7(User user){    System.out.println(user);    return "/success.jsp";}

发现POST乱码

解决post提交乱码我们可以配置spring提供的过滤器

characterEncodingorg.springframework.web.filter.CharacterEncodingFilterencodingUTF-8characterEncoding/*

4. SpringMVC常用注解

SpringMVC有一些数据是不能自动绑定,需要我们使用它提供的注解强制绑定.

遇到需要强制绑定的几种情况

a. 默认参数绑定的是表单数据,如果数据不是来自表单(如restful),那么必须需要强制绑定

b. 数据是来自表单的,但是参数名不匹配,那么也需要强制绑定

c. 数据是来自表单的,但是需要将数据绑定在Map对象里面,需要强制绑定

4.1. @PathVariable:绑定路径参数

这个注解是绑定路径参数的.

/** * http://localhost:8080/20/zhangsan/demo9.form * @param id * @param username * @return */@RequestMapping("/{id}/{username}/demo9")            //@PathVariable绑定restful请求public String demo9(    @PathVariable("id") Integer id,@PathVariable("username") String username    ){    System.out.println(id);    System.out.println(username);    return "/success.jsp";}
测试restful风个绑定

4.2. 通过@RequestParam绑定表单数据

接收的参数的变量名与表单的name属性不一样

/** * http://localhost:8080/demo8.form?name=zhangsan * @param username * @return */@RequestMapping("/demo8")            //@RequestParam强制数据类型绑定public String demo8(@RequestParam("name") String username) {    System.out.println(username);    return "/success.jsp";}
测试强制类型绑定

4.3. @CookieValue获得Cookie值的注解

/*** 获得JSP 页面,JSESSIOINID这个Cookie值* @param cookevalue*/@RequestMapping("/demo10")public void getcookie(@CookieValue(value="JSESSIONID") String cookevalue){    //输出Cookie    System.out.println(cookevalue);}
测试@CookieValue注解

4.4. @RequestHeader获得指定请求头的值

@RequestMapping("/demo11")//获取请求头host的值封装到value中public void demo10(@RequestHeader("host")String value){    System.out.println(value);}
测试@RequestHeader注解

4.5 @SessionAttributes 注解

把Model和ModelMap中的指定的key或者指定的属性的值也存入一份进session域

package com.dfbz.controller;import com.dfbz.entity.User;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.ui.ModelMap;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.SessionAttribute;import org.springframework.web.bind.annotation.SessionAttributes;import javax.servlet.http.HttpServletRequest;@Controller/** * names: 代表此类中model/modelMap的username属性将会添加到一份进入session * types: 此类中指定的类型会添加一份到session中 */@SessionAttributes(names = {"username"},types ={User.class,String.class,Integer.class} )public class Demo2Controller {    @RequestMapping("/demo12.form")    public String demo12(Model modelMap) {        modelMap.addAttribute("username","zhangsan");        modelMap.addAttribute("password","admin");        modelMap.addAttribute("age",20);        User user=new User();        user.setUsername("xiaodong");        modelMap.addAttribute("user",user);        return "/success.jsp";    }}
测试@SessionAttribute注解

@SessionAttribute注解:

从session中获取一个值封装到参数中

/** * @SessionAttribute:从session中获取一个值 * @param username * @param user * @return */@RequestMapping(value = "/demo6")public String demo5(@SessionAttribute("password") String username,@SessionAttribute("user") User user){    System.out.println(username);    return "/success.jsp";}

5. 格式化参数类型

SpringMVC之所以能够帮我们实现自动数据类型转换是因为SpringMVC提供了非常多的转换器(Converter)

例如:

1f3a13fbe1484315830a999545c4ab38
063de854f2ff40c1b460a59a0a51334e
986f67f6b6f14b9898883290d072cef6
e158caab8c5849b3a7824a5c992b4add

发现他们都实现Converter接口,如果我们需要之定义转换器必须实现Converter接口

案例:

实现日期的转换

实体类:

public class User {    private Integer id;    private String username;    private String password;    private String address;    private Date birthday;}

表单:

    Title    

controller:

@RequestMapping("/testConverter.form")public String testConverter(User user) {    System.out.println(user);    return "/success.jsp";}

转换器类:

package com.dfbz.converter;import org.springframework.core.convert.converter.Converter;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;/** * Converter */public class MyConverter implements Converter {    @Override    public Date convert(String str) {        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");        try {            Date date = sdf.parse(str);            return date;        } catch (ParseException e) {            e.printStackTrace();        }        return null;    }}

dispatcher-servlet.xml配置

六. Controller的生命周期

Spring框架默认创建的对象是单例.所以业务控制器是一个单例对象.

SpringMVC提供了,request,session ,globalsession三个生命周期

  • request:每次新的请求,创建一个新的实例.
  • session:每次会话创建一个新的实例. 就是同一个浏览器,就使用同一个实例
  • globalsession:基于集群的session

每个Session创建一个实例

package com.dfbz.controller;import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;@Controller//@Scope("request")           //代表每次请求都会创建一个新的Demo4Controller对象//@Scope("session")               //代表每次创建session就会创建一个Demo4Controller对象public class Demo4Controller {    public Demo4Controller(){        System.out.println("Demo4Controller创建啦!");    }    @RequestMapping("/demo4_1")    public String demo4_1(){        return "/success.jsp";    }}

at.support.FormattingConversionServiceFactoryBean">

六. Controller的生命周期

Spring框架默认创建的对象是单例.所以业务控制器是一个单例对象.

SpringMVC提供了,request,session ,globalsession三个生命周期

  • request:每次新的请求,创建一个新的实例.
  • session:每次会话创建一个新的实例. 就是同一个浏览器,就使用同一个实例
  • globalsession:基于集群的session

每个Session创建一个实例

package com.dfbz.controller;import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;@Controller//@Scope("request")           //代表每次请求都会创建一个新的Demo4Controller对象//@Scope("session")               //代表每次创建session就会创建一个Demo4Controller对象public class Demo4Controller {    public Demo4Controller(){        System.out.println("Demo4Controller创建啦!");    }    @RequestMapping("/demo4_1")    public String demo4_1(){        return "/success.jsp";    }}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值