sprig MVC学习总结

Spring MVC

提示:本文学习总结可能存在多处错误,浏览过程发现错误请在评论区描述



作用

是一个表现层框架,从请求中接收传入的参数,将处理后的结果返回给页面


一、请求的处理流程

1)------发起请求
2)------先发给tomcat服务器
3)------tomcat读取web.xml配置文件
4)------根据将请求给对应的中央调度器DispatcherServlet
5)------中央调度器拿到请求后,读取springmvc的配置文件,读取组件扫描器
6)------根据组件扫描器和请求扩展名知道给哪个控制器的哪个方法处理

1、用户发憷请求,请求被Spring MVC的前端控制器DispatcherServlet截获
2、DispatcherServlet对请求的URL进行解析,得到URI(请求资源标识符),然后根据URI,调用HandlerMapping获得该Handler配置的所有相关对象,包括Handler对象和Handler对象的拦截器,
3、DispatcherServlet根据获取的Handler,选择一个合适的HandlerAdapter。HandlerAdapter的设计符合对象中的单一实际处理请求结果
4、提取请求中的模型数据,开始执行Handler(Controller),在填充Handler的参数过程中,根据配置,spring将帮助做一些额外的工作
5、Handler执行完成后,会向DispatcherServlet返回一个ModelAndView对象,对于那些返回是String,Map,或者ModelMap的方法,Spring MVC也会在内部把它包装成一个ModelAndView对象。ModelAndView包含视图名或者视图模型。
6、DispatcherServlet根据返回的ModelAndView对象,选择一个合适的视图解析器(ViewResolver)
7、ViewResolver结合Model和View来渲染视图
8、DispatcherServlet将视图渲染结果返回给客户端

二、配置文件

1.配置中央调度器

<servlet>
        <servlet-name>myweb</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:conf/dispatcherServlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>myweb</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

中央调度器被创建之后,会调用Servlet的init()方法,在方法中创建springmvc容器对象,加载配置文件。自定义springMVC读取配置文件的位置<param-value>classpath:conf/dispatcherServlet.xml</param-value>,以及确定DispatcherServlet的创建时间<load-on-startup>1</load-on-startup>
创建springmvc容器对象的时候,默认读取的是/WEB-INF/-servlet.xml。
请求能使用的扩展名<url-pattern>方式有两种:以设定的扩展名结尾的请求都交给<servlet-name>对应的中央调度器。
1、*.xxx,xxx是自定义的扩展名,常用的有".do",“.action”等
2、使用斜杠“/”,在静态资源访问处记录

2、字符集过滤器

<filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>*</url-pattern>
    </filter-mapping>

CharacterEncodingFilter的有三个参数需要设置:
encoding:表示指定的字符集编码
forceRequestEncoding:表示是否同时设置Request的编码(true表示设置)
forceResponseEncoding:表示是否同时设置Response的编码(true表示设置)

<filter-mapping>

设置哪些请求需要使用指定字符集编码过滤。

3、视图解析器

<!--    springmvc的配置文件,声明controller和其他web相关的对象-->

    <context:component-scan base-package="com.SSM.controller"/>
    
<!--    视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

三、注解开发

先看看文件结构和内容

@Controller
@RequestMapping("/student")
public class StudentController {
    @RequestMapping("/show.do")
    public ModelAndView addshow(String name,String age){
        ModelAndView mv = new ModelAndView();
        mv.addObject("name",name);
        mv.addObject("age",age);
        mv.setViewName("show");
        return mv;
    }
}

常见注解

@Controller:表示在tomcat启动的时候,把这个类作为一个控制器加载到Spring的Bean工厂。
@RequestMapping:表示请求的
1、当@RequestMapping在类上边:表示请求的公共部分
2、当@RequestMapping在方法上边:表示请求的名称

请求方式

GET

默认请求是get的请求方式,当是get请求组方式,在控制器的方法上不需要做特殊的处理,或者也可以加上属性method=RequestMethod.GET

@RequestMapping("/some.do",method=RequestMethod.GET)
public ModelAndView doSome(){
.......
}

POST

当前端弄得请求指定了请求方式为POST请求,在控制器的处理方法上也需要配置属性。
post方式请求,中文会有乱码,需要使用过滤器处理乱码的问题

@RequestMapping("/some.do",method=RequestMethod.POST)
public ModelAndView doSome(){
.......
}

处理器方法的参数

处理器方法的采纳数可以有以下四种类型:
HttpServletRequest:请求
HttpServletResponse:应答
HttpSession:对话
请求中所携带的请求参数

  • 前三个参数框架会自动给他们赋值

HttpServletRequest,HttpServletResponse,HttpSession

这三个参数框架会自动赋值,不需要开发手动赋值

// 前端发起请求:http://localhost:8080/ch01_HttpServletRequest/some.do?name=zhangsan
@RequestMapping("/some.do")
public ModelAndView doSome(HttpServletRequest request){
		ModelAndView mv = new ModelAndView();
        mv.addObject("name=",request.getParameter("name"));
        mv.setViewName("show");
        return mv;
}
//  在show页面,能够显示name=zhangsan

请求中所携带的请求参数

逐个接收参数

要求:处理器方法的形参名和请求中的参数名称必须一致,同名的请求桉树赋值给同名的形参
前端请求

<form action="show.do">
        zhanghao:<input type="text" name="name">
        mima:<input type="text" name="age">
        <input type="submit" value="提交参数">
    </form>

后端控制器类接收参数

    @RequestMapping("/show.do")
    public ModelAndView dointerceptor(String name,Integer age) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("name",name);
        mv.addObject("age",age);
        mv.setViewName("show");
        return mv;
    }

在show.jsp页面能够获取name和age的值

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

<h2>接收的name参数值:${name}</h2>
<h2>接收的age参数值:${age}</h2>

</body>
</html>

原理:框架接收请求的参数
1、使用request对象接收参数
------String name = request.getParameter(“name”);
------String age = request.getParameter(“age”)
2、springmvc框架通过中央调度器调用控制器的dodointerceptor()方法,按名称对应,把接收的参数赋值给形参,框架会提供类型转换的功能

@RequestParam注解

当请求中的参数和处理器方法的形参不一致的时候,可以使用这个注解来解决名称不一致的问题
@RequestParam("请求中的参数名称”)
前端:

<form action="show.do">
        zhanghao:<input type="text" name="myname">
        mima:<input type="text" name="myage">
        <input type="submit" value="提交参数">
    </form>

后端控制器

    @RequestMapping("/show.do")
    public ModelAndView dointerceptor(@RequestParam("myname")String name,@RequestParam("myage")Integer age) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("name",name);
        mv.addObject("age",age);
        mv.setViewName("show");
        return mv;
    }
对象接收方案

需要一个保存请求参数的普通类,并且这个类的属性名和请求的参数名要一样
在这种方式中,@RequestParam注解没有作用

前端代码:

<form action="show.do">
        zhanghao:<input type="text" name="myname">
        mima:<input type="text" name="myage">
        <input type="submit" value="提交参数">
    </form>

后端代码:

// 创建一个保存请求参数的普通类
public class Student{
	private String myname;
	private Integer myage;

	// 添加set和get方法

	// 无参构造方法
}

//控制器类的方法
    @RequestMapping("/show.do")
    public ModelAndView dointerceptor(Student mystudent) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("name",mystudent.getMyname());
        mv.addObject("age",mystudent.getMyage());
        mv.setViewName("show");
        return mv;
    }

返回类型

返回的数据类型可以有一下几种:
1、ModelAndView
2、String
3、void
4、Object对象

ModelAndView

有数据和视图,对视图进行forward操作

String

只是页面的跳转

处理器方法返回String表示视图名称。当return视图的完整视图路径,则不能配置视图解析器
前端请求

<form action="show.do">
        zhanghao:<input type="text" name="name">
        mima:<input type="text" name="age">
        <input type="submit" value="提交参数">
    </form>

后端处理器方法

//控制器类的方法
    @RequestMapping("/show.do")
    public String dointerceptor(HttpServletRequest request,String name,Integer age) {
    	// 可以自己手工添加数据到request作用域
    	// request.setAttribute("name",name);
    	// request.setAttribute("age",age);
        return "show";
    }

return返回逻辑视图名称,框架对视图执行forward转发操作

String表示数据

区分 String是比哦啊还是视图还是数据,看方法上是否有注解@ResponseBody,有这个注解String表示数据,反之,String表示视图

  • @ResponseBody
    作用:把处理器方法返回对象转为json后,通过HttpServletResponse输出给浏览器
    位置:方法定义的上边
@RequestMapping(value = "/returnStringData.do",produces = "text/plain;charset=utf-8")
    @ResponseBody
    public String doStringData(String name,Integer age){
        return "Hello SpringMVC 返回对象,表示数据";
    }

问题:
String表示数据,数据包含中文传到前端会出现乱码,前端默认的编码格式是text/plain;charset=ISO-8859-1
解决办法:在@RequestMapping注解中设置属性produces = “text/plain;charset=utf-8”

void

不能表示视图,也不能表示数据,一般用在ajax应答操作上。

$.ajax({
	url:"dosome.do",
	data:{
		name:"zhangsan",
		age:20
	},
	type:"post",
	dataType:"json"
	success:function(resp){
		alert(resp);
	}
})
    @RequestMapping(value = "/returnVoid-ajax.do")
    public void doReturnVoidAjax(HttpServletResponse response, String name, Integer age) throws IOException {
        System.out.println("===doReturnVoidAjax====, name="+name+"   age="+age);
       //处理ajax, 使用json做数据的格式
       //service调用完成了, 使用Student表示处理结果
        Student student  = new Student();
        student.setName("张飞同学");
        student.setAge(28);

        String json = "";
        //把结果的对象转为json格式的数据
        if( student != null){
            ObjectMapper om  = new ObjectMapper();
            json  = om.writeValueAsString(student);
            System.out.println("student转换的json===="+json);
        }

        //输出数据,响应ajax的请求
        response.setContentType("application/json;charset=utf-8");
        PrintWriter pw  = response.getWriter();
        pw.println(json);
        pw.flush();
        pw.close();

    }

静态资源访问

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

当配置“/”,导致所有的请求包括静态资源都交给DispathcherServlet处理,默认情况下DispathcherServlet没有处理静态资源的能力,没有控制器能处理静态资源访问请求,所以静态资源(html,图片,js)都是404。

为了解决DispathcherServlet能够处理静态资源的访问,解决办法有两种
1、在springmvc配置文件中使用<mvc:default-servlet-handler/>
tomcat的web.xml文件有一个servlet 名称是 default , 在服务器启动时创建的。
表示访问静态资源和未映射的请求都是有default处理

注意:由于<default-servlet-handler/>和@RequestMapping注解有冲突,需要加入<mvc:annotation-driven/>

<?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 
       https://www.springframework.org/schema/context/spring-context.xsd 
       http://www.springframework.org/schema/mvc 
       https://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!--    加入注解驱动-->
    <mvc:annotation-driven/>
    <!--    静态资源访问===================================================================-->
    <mvc:default-servlet-handler/>
    <!--    静态资源访问===================================================================-->

</beans>

原理是加入这个标签后,框架会创建控制器对象DefaultServletHttpServletHandler,当接收到静态请求后,DefaultServletHttpServletHandler会吧请求转发给tomcat的default这个servlet。
2、在springmvc配置文件中使用<mvc:resources mapping="" location=""/>标签。
加入这个标签,框架会创建ResourceHttpRequestHandler这个处理器对象,让这个对象处理静态资源访问请求,不依赖tomcat服务器。
mapping:访问静态资源的url地址,使用通配符 **
location:静态资源你在项目中的位置

	<mvc:resources mapping="/image/**" location="/static/image/"/>
    <mvc:resources mapping="/html/**" location="/static/image/"/>
    <mvc:resources mapping="/js/**" location="/static/image/"/>

相对路径和绝对路径

在页面(jsp,HTML)中使用的地址,都是前端页面的地址,都是相对地址
地址分类
1、绝对地址:带有协议名称的都是绝对地址,例如:https://editor.csdn.net
2、相对地址:没有协议开头的,例如 user/some.do,/user/some.do。相对地址不能单独使用,必须有一个参考地址,通过参考地址+相对地址本省才能制定资源
3、参考地址:
访问地址不加“/”

<!--index.jsp-->
<p><a href="user/some.do">发起请求</a></p>

访问地址:http://localhost:8080/ch01_path/index.jsp
路径:http://localhost:8080/ch01_path/
资源:index.jsp

在index.jsp页面发起user/some.do,浏览器的访问地址就会变成http://localhost:8080/ch01_path/user/some.do
所以:没有斜杠的请求,点击链接,访问地址变成当前页面的路径 + 链接的地址

访问地址加"/"

<!--index.jsp-->
<p><a href="/user/some.do">发起请求</a></p>

访问地址:http://localhost:8080/ch01_path/index.jsp
路径:http://localhost:8080/ch01_path/
资源:index.jsp

在index.jsp页面发起user/some.do,浏览器页面访问地址会变成http://localhost:8080/user/some.do,少了项目名称部分。参考地址则变成http://localhost:8080/
这样页面访问是空白,失败的,要想访问成功,可以使用EL表达式(${pageContext.request.contextPath})那么,访问的链接地址变成href="${pageContext.request.contextPath}/user/some.do",这样就可以正常访问。

 前提:在后端控制器设置在index.jsp页面some.do请求后访问的页面还是index.jsp。
  index.jsp  访问 user/some.do  , 返回后现在的地址: http://localhost:8080/ch06_path/user/some.do

  http://localhost:8080/ch06_path/user/some.do
  路径:	  http://localhost:8080/ch06_path/user/
  资源:   some.do

  在index.jsp在 user/some.do ,就变为 http://localhost:8080/ch06_path/user/user/some.do

  解决方案:
   1.加入${pageContext.request.contextPath}
	2.加入一个base标签, 是html语言中的标签。 表示当前页面中访问地址的基地址。
	  你的页面中所有 没有“/”开头的地址,都是以base标签中的地址为参考地址
    使用base中的地址 + user/some.do 组成访问地址

base标签

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String basePath=request.getScheme()+"://"
    +request.getServerName()+":"+request.getServerPort()
    +request.getContextPath()+"/";
%>
<html>
<head>
    <title>功能rukou //  /SSM_war_exploded</title>
    <base href="<%=basePath%>"/>
</head>

转发和重定向

在这里插入图片描述
foeward转发:向资源1发起请求,由于资源1处理没有达到理想结果,在服务器内部,将请求转发给资源2,由资源2来处理请求,再将结果返回。
redirect重定向:向资源1发起请求,由于资源1处理没有达到理想结果,返回浏览器放问资源2能处理请求,浏览器会自动发起第二次请求访问资源2,然后返回结果。区别于转发,重定向进行了两次访问。
面试解答
1、重定向是浏览器发送请求并得到响应,以后向一个新地址发起请求,转发是服务器收到请求后,为完成请求处理而转到另外一个资源进行处理。浏览器只发起一次请求。
2、重定向请求两次,不产生共享数据,转发请求一次,共享数据
3、重定向后地址会发生变化,转发不会发生变化
4、重定向的新地址可以是任意地址,转发必须是同一个应用下的某个资源文件。

拦截器

需要在springmvc配置文件中添加配置

<!--    声明拦截器-->
    <mvc:interceptors>
<!--        定义第一个拦截器-->
        <mvc:interceptor>
<!--            指定拦截的请求url地址
                任何以user开头的请求,都要拦截
-->
            <mvc:mapping path="/student/interceptor.do"/>
<!--            <mvc:mapping path="/**"/>任意请求都要被拦截-->
<!--            声明拦截器对象-->
            <bean class="com.SSM.interceptor.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

MyInterceptor是程序中自定义的一个拦截器对象,这个拦截器对象要实现HandlerInterceptor接口
在这个接口中实现类中,需要实现三个方法,
1、preHandle预处理方法

返回值:
 true:通过验证,后续执行
 拦截器MyInterceptor的preHandle()方法
 controller方法开始执行
  拦截器MyInterceptor的postHandle()方法
  拦截器MyInterceptor的afterCompletion()方法
 
  false:验证失败,请求到达拦截器就截止了
 只执行拦截器MyInterceptor的preHandle()方法
 
  验证通过,执行控制器方法
 验证失败,阶段请求,请求不能被处理

2、postHandle后处理方法:
处理器方法执行之后执行,可以对处理器方法的执行结果做二次修改

3、afterCompletion:
最后执行的方法,请求处理完成后执行的,经常做资源回收,删除对象和清理内存

/**
 * 拦截器类,拦截用户的请求
 */
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器MyInterceptor的preHandle()方法");
        // 验证失败,给浏览器一个反馈
        //request.getRequestDispatcher("/terceptortip.jsp").forward(request,response);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("拦截器MyInterceptor的postHandle()方法");
        if (modelAndView != null){
            modelAndView.addObject("date",new Date());
            modelAndView.setViewName("other");
        }
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("拦截器MyInterceptor的afterCompletion()方法");
    }
}

当程序中包含多个拦截器的时候,在配置文件中就需要声明多个拦截器
当对同一个请求有多个拦截器处理的时候,哪个拦截器先声明,就限制性哪个拦截器的preHandle()方法。

假如111111拦截器先声明,那么

执行流程如下
111111-拦截器的MyInterceptor的preHandle()
22222-拦截器的MyInterceptor的preHandle()
=-=执行MyController中的doSome方法=====
22222-拦截器的MyInterceptor的postHandle()
111111-拦截器的MyInterceptor的postHandle()
22222-拦截器的MyInterceptor的afterCompletion()
111111-拦截器的MyInterceptor的afterCompletion()

当第一个拦截器的preHandle()是true,第二个拦截器的preHandle()是false,

执行流程 111111-拦截器的MyInterceptor的preHandle()
22222-拦截器的MyInterceptor的preHandle()
111111-拦截器的MyInterceptor的afterCompletion()

两个都是false

111111-拦截器的MyInterceptor的preHandle()


总结

不能有总结,还没学完呢,下一篇是mybatis的学习总结,有问题请评论出来,我再改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值