JAVA-SpringMVC-1

SpringMVC

一、SpringMVC是什么

• 是基于spring的一个框架,实际上就是spring的一个模块,专门做web开发的
• 可以理解为Servlet的升级
• web开发底层就是Servlet,框架是在Servlet基础上面添加一些功能,做web项目更方便
• SpringMVC能够创建对象,放入到容器中(SpringMVC的容器) SpringMVC里面放的是控制器对象
• 我们要做的是使用@Controller注解创建控制器对象,把对象放入到SpringMVC容器中,把创建的对象作为控制器使用
• 这个控制器对象能接收用户的请求,显示处理结果,就当作是一个servlet使用【并不是servlet,就是普通对象】
    • 使用@Controller创建的对象,其实就是个普通的对象,springMVC赋予了他控制器的能力
• Springmvc底层访问依然是DispatcherServlet   他的两大作用:
    • 创建WebApplicationContext对象,读取配置文件,进而控制控制器对象
    • 本身就是一个Servlet,要接收请求,显示结果

二、springMVC的工作模式

• web开发底层时servlet,springmvc中有一个对象是Servlet:DispatcherServlet(中央调度器)   负责接收用户所有请求,然后把请求转发给Controller对象,最后是Controller对象处理请求
    • Index.jsp------>DispatherServlet------>转发,分配给----->Controller对象(@Controller注解创建的对象)

完整的工作流程

1.用户发送请求至 前端控制器DispatcherServlet。
2.前端控制器DispatcherServlet收到请求后调用处理器映射器HandlerMapping。
3.处理器映射器HandlerMapping根据请求的Url找到具体的处理器,生成处理器对象Handler及处理器拦截器HandlerIntercepter(如果有则生成)一并返回给前端控制器DispatcherServlet。
4.前端控制器DispatcherServlet通过处理器适配器HandlerAdapter调用处理器Controller。
5.执行处理器(Controller,也叫后端控制器)
6.处理器Controller执行完后返回ModelAnView。
7.处理器映射器HandlerAdapter将处理器Controller执行返回的结果ModelAndView返回给前端控制器DispatcherServlet。
8.前端控制器DispatcherServlet将ModelAnView传给视图解析器ViewResolver。
9.视图解析器ViewResolver解析后返回具体的视图View。
10.前端控制器DispatcherServlet对视图View进行渲染视图(即:将模型数据填充至视图中)
11.前端控制器DispatcherServlet响应用户。

三、SpringMVC入门案例

1、创建maven项目,webapp

因为maven创建的web项目中的 web.xml文件是 2.3版本的,需要重新创建一下

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
</web-app>

2、加入依赖 spring-mvc 、servlet、

<!--springMVC的依赖-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.2.5.RELEASE</version>
</dependency>

会间接的把spring的依赖都加入到项目中,

3、在web.mxl文件中,注册springmvc框架的核心对象 DispatcherServlet

• DispatcherServlet :中央调度器【父类继承Servlet,本身就是Servlet,具备所有servlet的功能】
• DispatcherServlet:也叫前端控制器
    • 负责去接收用户提交的请求,调用其他的控制器对象 ,并把请求的处理结果显示给用户

<servlet>
    <!--springmvc在创建容器对象时,读取的配置文件默认是 /WEB-INF/<servlet-name>-servlet.xml
        也就是说 读取的就是下面这个name 后面加 -servlet.xml, 
        因为这个规则不方便,所以就不用这个默认的规则,去自定义文件所在的位置-->
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--设置在服务器启动时,马上创建DispatcherServlet对象-->
    <!--load-on-startup:在启动时进行加载,
        数字表示tomcat启动后创建的顺序,数制越小创建的对象时机越早 >=0的整数-->
        
    <!--自定义文件所在位置-->
    <init-param>
        <!--指定SpringMVC的配置文件的属性,必须是contextConfigLocation-->
        <param-name>contextConfigLocation</param-name>
        <!--自定义文件的位置 classpath:-->
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<!--设置servlet-mapping-->
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <!--可以使用两种值,
    1.使用扩展名的方式,语法*.xxxxxx是自定义的拓展名常用的有*.do*.action*.mvc
        表示以.do结尾的请求,都会被该servlet-mapping处理 (没有/)
        http://localhost:8080/myweb/some.do
        http://localhost:8080/myweb/other.do
    2.使用"/"的方式 
    -->
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

4、创建发起请求的页面

5、创建控制器类/后端控制器 @Controller

1. 在类的上面加入@Controller注解,创建对象,放入到SpringMVC容器中

2. 在中的方法上加入@RequestMapping注解

• 方法是自定义的,可以有多种返回值,多种参数,方法名称自定义
• 被@RequestMapping注解修饰的方法叫处理器方法

@RequestMapping("/login.do")
public ModelAndView doSome(){
    ModelAndView wv = new ModelAndView();
    return wv;
}

6、创建springMVC的配置文件

(和spring的配置文件一样)

1. 声明组件扫描器,指定controller注解所在的包名

• 在resources目录下创建springmvc配置文件,和spring配置文件一样
• 声明组件扫描器 <context:component-scan base-package="com.yixuexi"/>

2. 声明视图解析器,帮助开发人员设置视图文件的路径

• 为了防止用户恶意访问show.jsp, 把show.jsp放到 WEB-INF目录下,这样用户不可能在地址框搜索到
• 配置视图解析器

<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <!--前缀,视图文件的路径-->
  <property name="prefix" value="/WEB-INF/view/"/>
  <!--后缀,视图文件的拓展名-->
  <property name="suffix" value=".jsp"/>
</bean>

• 在WEB-INF目录下有一个 view目录,里面放着 show.jsp

3. 注意:springmvc配置文件的名字要和web.xml文件中的这个属性中的值一致

为什么要在tomcat启动后,创建DispatcherServlet对象实例

• 因为,DispatcherServlet在他创建的过程中,会同时创建springmvc容器对象,
• 读取springmvc的配置文件,把配置文件中的对象都创建好,当用户发起请求时就可以直接使用对象了

总结

1. 先导入依赖
2. 然后在web.xml文件中,创建DispachterServlet对象
3. 然后创建类 在类上添加@Controller注解,
4. 然后创建方法,方法返回值类型为ModelAndView, 方法名随意
5. 方法上添加@RequestMapping注解 value属性写 请求的uri地址,就是/login.do  或者 /register.do
6. 在springmvc的配置文件中,声明组件扫描器,和视图解析器
7. 然后处理完之后,可以在mv那个对象上,进行添加数据 addObject(key,value);  setViewName("视图文件")

四、返回值ModelAndView对象使用

ModelAndView mv = new ModelAndView();
//指定数据,添加数据,框架在最后把数据放到了request作用域中
//相当于 request.setAttribute("key","value"); 框架帮你做了
mv.addObject("key","欢迎使用mvc做web开发");
mv.addObject("function","执行的时doSome()方法");
//指定视图,指定视图的完整路径
//框架对视图执行的是forward操作,(请求转发)//request.getRequestDispatcher().forward() 框架帮你做了
mv.setViewName("/show.jsp"); //没有配置视图解析器的时候,show.jsp还在webapp目录下
//配置了视图解析器的时候,show.jsp在WEB-INF/view下,后缀也省了
//直接使用文件的名称就可以了,框架自己去/WEB-INF/view/下去找show.jsp
mv.setViewName("show")
说明:
    使用@RequestMapping修饰的方法叫做处理器方法/通知器方法
    使用@RequestMapping修饰的方法是可以处理请求的,类似于Servlet中的doGet() doPost()
    返回值:ModelAndView : 本次请求的处理结果
         Model:数据,请求处理完成后,要显示给用户的数据
         View:视图,比如jsp/html等等的

五、SpringMVC web.xml 固定配置

web.xml 固定代码

<!--web.xml固定代码-->
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--设置在服务器启动时,马上拆功能键DispatcherServlet对象-->
    <!--load-on-startup:在启动时进行加载,
    数字表示tomcat启动后创建的顺序,数制越小创建的对象时机越早>=0的整数-->
    <init-param>
        <!--指定SpringMVC的配置文件的属性,必须是contextConfigLocation-->
        <param-name>contextConfigLocation</param-name>
        <!--自定义文件的位置classpath:-->
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<!--设置servlet-mapping-->
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <!--可以使用两种值,
    1.使用扩展名的方式,语法*.xxxxxx是自定义的拓展名常用的有*.do*.action*.mvc
        表示以.do结尾的请求,都会被该servlet-mapping处理(没有/)
            http://localhost:8080/myweb/some.do
            http://localhost:8080/myweb/other.do
    2.使用"/"的方式
    -->
    <url-pattern>/</url-pattern>
</servlet-mapping>
<!--注册过滤器,解决post请求中文乱码问题 web.xml文件配置-->
<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <!--CharacterEncodingFilter-->
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--设置项目中使用的字符编码-->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
    <!--强制请求对象,使用encoding编码的值-->
    <init-param>
        <param-name>forceRequestEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
    <!--强制响应对象,使用encoding编码的值-->
    <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>

springmvc.xml 固定代码

<!--组件扫描器,用来扫描注解创建对象的-->
<context:component-scan base-package="com.yixuexi"/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!--前缀,视图文件的路径-->
    <property name="prefix" value="/WEB-INF/view/"/>
    <!--后缀,视图文件的拓展名-->
    <property name="suffix" value=".jsp"/>
</bean>
<!--springmvc响应AJAX 请求返回一个json数据的对象 添加注解驱动-->
    <mvc:annotation-driven/>
<!--url-pattern是/时,配置访问静态文件,目录要求:静态文件都在static文件下-->
<!--同时也需要上面那一句 <mvc:annotation-driven>-->
    <mvc:resources mapping="/static/**" location="/static/"/>
    
拦截器
<!--声明拦截器,在框架中拦截器可以有0或多个-->
<mvc:interceptors>
    <!--声明第一个-->
    <mvc:interceptor>
        <!--指定拦截的请求uri地址的
            path:就是uri地址,可以使用通配符 **
            **:表示任意的字符,文件,或者多级目录和目录中的文件
            /** : 表示所有的请求都会被拦截
        -->
        <mvc:mapping path="/**"/>
        <!--声明拦截器对象,表示访问上面那个地址的时候都由下面这个拦截器处理-->
        <bean class="com.yixuexi.handler.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

六、@RequestMapping注解

准备使用doSome()方法处理前端页面发来的login.do的请求
@RequestMapping:请求映射,作用是把一个请求地址和一个方法绑定在一起
一个请求指定一个方法处理

1、属性:

1.value: 表示请求的uri地址 唯一值【login.do】
    • 在使用时,推荐以“/”开头
    • 可以是数组,{"/xxx","/xxx","/xxx"}      (多个请求一个方法处理)
2.method:表示请求的方式,他的值是RequestMethod的枚举值
    • 如果没有指定的话,所有的请求方式都可以访问
    • 例如表示get请求方式, RequestMethod.GET 或者.POST
    • 如果该方法用的post请求,那么请求必须是post才能访问该方法【表单可以发post请求】 不按照对应的请求方式 报错 405
    • 前端发送请求 开头不需要 / 

2、位置

1. 在方法的上面【表示这个方法处理这个请求】
2. 在类的上面  【集中的定义,把公用的提取出来】
    a.  value: 所有请求地址的公共部分 ,也叫模块名称
    b. 如果请求是这样的 test/login.do     test/register.do  的话就可以在类的上面添加@RequestMapping("/test")       注解,那么他的方法就不用加 "/test" 了 直接      /login.do就行了

七、请求的处理流程

1、springmvc请求的处理流程

第⼀步:⽤户发送请求⾄前端控制器DispatcherServlet
第⼆步:DispatcherServlet收到请求调⽤HandlerMapping处理器映射器
第三步:处理器映射器根据请求Url找到具体的Handler(后端控制器),⽣成处理器对象及处理器拦截器(如果 有则⽣成)⼀并返回DispatcherServlet
第四步:DispatcherServlet调⽤HandlerAdapter处理器适配器去调⽤Handler
第五步:处理器适配器执⾏Handler
第六步:Handler执⾏完成给处理器适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回 ModelAndView,ModelAndView 是SpringMVC 框架的⼀个底层对 象,包括 Model 和 View
第⼋步:前端控制器请求视图解析器去进⾏视图解析,根据逻辑视图名来解析真正的视图。
第九步:视图解析器向前端控制器返回View
第⼗步:前端控制器进⾏视图渲染,就是将模型数据(在 ModelAndView 对象中)填充到 request 域
第⼗⼀步:前端控制器向⽤户响应结果

2、springmvc执行过程分析 init源码分析

2.1 tomcat启动,创建容器的过程

1. tomcat启动,先执行web.xml文件,然后通过load-on-startup标签中的1创建DispatcherServlet对象 
2. DispatcherServlet他的父类是继承HttpSerlvet的,他是一个Serlvet,在被创建时,会执行init方法。
3. 在inut方法中会执行 new ClassPathWebApplicationContext("文件地址");      并把它放到全局作用域中
4. 创建了容器,容器同时也创建了@Controller注解所在的对象,
5. 这个controller对象放入到了springmvc的容器中,

3、组件说明

1. DispatcherServlet
前端控制器
用户请求到达前端控制器,它就相当于mvc中的c,DispatcherServlet是整个流程控制的中心,由他调用其他组件处理用户的请求,DispatcherServlet的存在降低了组件之间的耦合度

2. HandlerMapping
处理器映射器
HandlerMapping 负责根据用户发送的请求 uri 来找到对应的controller中的方法
springmvc提供了不同的映射器实现不同的映射方式,HandlerMapping会把找到映射返回给DispatcherServlet

3. Handler / controller
后端控制器
在DispatcherServlet的控制下,Handler对具体的用户请求进行处理

4. HandlerAdapter
通过HandlerAdapter对处理器进行执行,处理器适配器

5. ViewResolver
View Resolver 负责将结果转换成view 视图

6. View
SpringMVC框架提供了很多的View视图类型的支持
包括:jstlView,freemarkerView,pdfView,我们最常用的视图就是JSP

八、处理器方法的形参

处理器方法可以包含以下4类参数,这些参数springmvc会给自动赋值,直接使用就行
直接在处理器方法里面定义形参即可

1. HttpServletRequest    请求 
2. HttpServletResponse  响应
3. HttpSession   会话
4. 请求中锁携带的请求参数

@RequestMapping(value="/login.do",method=RequestMethod.POST)
//直接在这里声明 上请求对象,响应对象,session对象就行
Public ModelAndView test(HttpSession session,
                         HttpServletRequest request,
                         HttpServletResponse response){
    //从请求中得到数据 getParameter()
    String username = request.getParameter("username");
    ModelAndView mv=new ModelAndView();
    //添加到mv对象中,也就是请求作用域对象
    mv.addObject("key",username);
    //请求转发,到login.jsp, 这里配置了视图解析器,本来应该写 /WEB-INF/view/login.jsp的
    mv.setViewName("login");
    returnmv;
}

1、获取请求中携带的请求参数

1.1 逐个获取

要求:
• 处理其方法的形参名,和请求中参数的name必须一致。
• 同名的请求参数会自动赋值给同名的形参

@RequestMapping(value="/login.do",method=RequestMethod.POST)
//逐个接收,形参名必须和参数名一致才行
public ModelAndView login(String username,String password){
    ModelAndView mv=new ModelAndView();
    mv.addObject("key",username);
    mv.setViewName("login");
    return mv;
}

• 框架内部完成了 String username = request.getParameter("username");
• 框架会提供类型转换的功能,能把String转换成int,long,float,double 等类型和他的包装类型。
• 注意:当提交的是空字符串 "",或者是"abc"时,无法进行int类型转换,所以会报错400
• 状态码400:所有4xx报错都是客户端问题,400表示提交请求参数的时候,发生了问题。
• 建议使用包装类,不要使用基本数据类型,容易出错(但还是不能转换adc这种的,"" 不会报错)

1.2 对象接收

(参数多的话,使用对象接收会比较好)
创建一个类,类中的属性名和参数名一致,提供get set 方法和无参构造。
框架自动调用无参构造创建对象,再调用set方法 设置值。
前端发来的参数名称是name,框架自动调用 setName()方法
形参中也可以有多个对象,比如Student, School,Address

2、解决请求中参数和方法形参不一致

前端发来的请求,参数名是 xingming,mima
只能用在逐个接收的方案中

2.1 @RequsetParam注解:

解决请求中参数名形参名不一致的问题

属性:
value:请求中参数的名称。
required:是要给布尔类型 [必须的]
true:表示这个请求中必须包含此参数。
false:如果没有这个参数也可以
位置:
在处理器方法的形参定义前面

@RequestMapping("/login")
public String login(@RequestParam("xingming") String username
                    @RequestParam("mima") String password
){
}

九、处理器方法的返回值

1、返回ModelAndView

1. ModelAndView mv = new ModelAndView();
2. 返回数据部分 mv.addObject("key","zhangsan"); 最后是放到了request作用域中
3. 返回视图部分 mv.setViewName("show");前提是SpringMvc配置了视图解析器。
4. 如果页面发送的是AJAX请求,页面不会进行跳转,那么setViewName()方法就显得很多余,所以这里使用ModeAndView作为返回值就不在合适。
5. 同时需要保存数据,同时需要跳转页面,这样的话就使用ModelAndView

2、返回String表示视图部分

如果本次请求,仅仅是要做的一个页面跳转的功能,那么使用String作为返回值最好
可以使用逻辑名称【文件名】,也可以是完整路径。
程序内部执行的是 forward() 请求 请求转发

使用逻辑名称:
• return “doSome” 【配置了视图解析器,拼接后的完整路径为/WEB-INF/view/doSome.jsp】

使用过完整视图路径:
• 项目中不能配置视图解析器
• return “/WEB-INF/view/doSome.jsp”

请求转发:
• return “redirect:/doSome”; 【调转到doSome路由】

3、返回值void

既不能表示数据,也不能表示视图
在处理AJAX时,可以使用void,通过HttpServletResponse来输出数据,响应AJAX请求。
AJAX请求服务器端返回的就是数据,和视图无关。
当接受到ajax请求时,需要返回数据,只需要往HttpServletResponse的print();方法里写就行。

修改响应字符集
response.setContentType("text/html,charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print("响应AJAX请求");

4、返回值Object 【处理AJAX】

返回:String、Integer、Map、List、Student 等等都是对象。
对象有属性,属性就是数据,所以返回Object表示返回数据,和视图无关
可以使用对象表示的数据,来响应AJAX请求
现在做AJAX,主要是使用JSON的数据格式,处理器返回Json数据实现步骤:

①、加入Json

springmvc默认使用的是jackson 【一个自动生成json的jar包】

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.11.0</version>
</dependency>

②、把java对象转换成json

在springmvc配置文件中加入&#60;mvc:annotation-driven&#62; 注解驱动。这样就好了
在加入到springmvc中,会自动创建HttpMessageConverter接口,和他的7个实现类对象
③、在处理器方法的上面加入 @ResponseBody注解
放在处理器方法的上面,通过HttpServletResponse来输出数据,响应AJAX请求的
处理器方法返回一个Student,通过框架转为json,响应ajax请求

@ResponseBody
• 作用:把处理器方法返回的对象转换为json数据后,通过HttpServletResponse输出给浏览器
• 位置:在方法定义的上面

例如:处理器方法返回一个Student对象,通过框架转为json,响应ajax请求

@ResponseBody
@RequestMapping("/test")
public Student test(){
    return new Student();
}

例如:返回一个List集合,里面是Student

4、处理器方法返回一个String,并不是视图信息,而是数据

• 区分返回值字符是数据还是视图,看有没有@ResponseBody注解
• 如果有就是数据,如果没有就是视图

@RequestMapping("处理地址")
@ResponseBody
public String returnString(){
    return "登录失败";
} //有@ResponseBody注解,是数据,不是视图

出现的问题: 返回中文的时候出现乱码问题 “???”
解决方案:给@RequestMapping注解增加一个属性
@RequestMapping(value = “/returnStudentJson.do”,produces = “text/html;charset=utf-8”)

十、解读url-pattern

在servlet-Mapping中的url-pattern中使用 /

<servlet-mapping>
  <servlet-name>springmvc</servlet-name>
  <url-pattern>/</url-pattern> 【这样就可以不用some.do了,就是some了】
</servlet-mapping>

• 导致所有的静态资源请求都交给了DispatcherSerlvet处理,默认情况下DispatcherServlet没有处理静态资源的能力。没有控制器对象能对静态资源的访问,
• 所有静态资源都是404【图片,js,html,css】

(当中央调度器的url-pattern设置为/ 之后 静态资源访问会失败 404 ,动态资源可以正常访问)

1、第一种处理静态资源无法访问的方式

需要在springmvc的配置文件中加入 &#60;mvc:default-servlet-handler&#62;

• 加入这个标签后,框架会创建一个default对象,他像是一个监察员,对请求中的uri进行筛查,如果是访问静态资源,那么 他做处理。【注意 这里要加入 <mvc:annotation-driven/> 注解驱动,要不动态资源无法访问,有冲突,至于什么冲突,负负得正吧…】

<mvc:default-servlet-handler/>
<mvc:annotation-driven/>

2、第二种处理静态资源无法访问的方式【常用】

在springmvc的配置文件中添加该标签

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

• 属性:
    • Mapping: 访问静态资源的uri,使用统配符  **  [两个星星]
    • Location:静态资源在项目中的目录
• 作用:
    • 加入该标签后,框架会创建 ResourceHttpRequestHandler对象,让这个对象去处理静态资源的访问。
• 注意:还需要添加上json的注解驱动标签 不然有冲突
    • <mvc:annotation-driven/>
• 常用
    <mvc:resources mapping="/static/**" location="/static/"/>
    <mvc:annotation-driven/>

十一、路径问题

在jsp/html中路径是使用 /开头 还是不用 / 开头 ?

1、地址分类:

相对地址:除绝对地址其余都是相对地址 user/some.do /user/some.do
相对地址不能独立使用,必须要有一个参考地址,通过参考地址+相对地址=访问地址
绝对地址:带有协议名称的。 http://www.baidu.com

2、处理方案

Jsp/html文件上有一个 user/some.do 的请求,链接
当你的地址没有斜杠 / 开头,点击链接时,访问地址是当前页面的地址 加上 链接的地址 【不建议使用】

• 参考地址 :Http://localhost:8080/myWeb/ + user/some.do

会出现的问题:

• 当网页路径是 Http://localhost:8080/myWeb/user/some.do时 在去访问 user/some.do时,路径就会变成 Http://localhost:8080/myWeb/user/user/some.do,  此时就会出现404问题【找不到】

解决方案:

• 添加EL表达式
<a href="${pageContext.request.contextPath}/user/some.do"> 链接</a>
• 加入一个base标签
表示当前页面中访问地址中的基地址 【你的页面中所有 没有以“/” 开头的地址,都是以base中的地址为参考地址】

使用base中的地址 + user/some.do 组成访问地址
&#60;base href=”http://localhost:8080/myWeb/"/>

当你的地址有斜杠 / 开头,点击链接时,访问的是服务器地址 加上 链接的地址

• 参考地址 :Http://localhost:8080 + /user/some.do
• 解决方案:在访问的链接上 加上项目名    <a href="/myWeb/user/some.do">链接</a>

3、在项目中遇到了 / 开头的路径时,可加入${pageContext.request.contextPath}

<a href="${pageContext.request.contextPath}/user/some.do"> 链接</a>

4、通过代码获取项目的路径,base可以直接使用获取到的

<%
   //获取项目路径,到myWeb项目那里
   String basePath = request.getScheme() + "://" +
   request.getServerName() + ":" + request.getServerPort() +
   request.getContextPath() + "/";
   %>
  <title>Title</title>
  <base href="<%=basePath%>">
  <a href="user/doSome">aaaaaaaaaaa</a>   
  //在使用了base之后,就不需要添加/开头了,因为base会将没有以斜杠开头的地址,把参考地址改为base地址

十二、请求转发和重定向

• springmvc对请求转发和重定向操作进行了封装,现在可以使用简单的方式实现请求转发和重定向
• forward:表示请求转发,实现request.getRequestDispatcher("xx.jsp").forward();
• redirect:表示重定向,实现response.sendRedirect("xxx".jsp)
• forwar和redirect都是框架的关键字,有一个共同的特点,他们都不和视图解析器一同工作。

1、forward

处理器方法返回ModelAndView,实现请求转发 forward

语法:mv.setViewName(“forward:/视图文件完整路径”)

特点:不和视图解析器一同使用,就当项目中没有视图解析器
就算有视图解析器,也得写上前缀 后缀
显式转发,明显的说明这是转发,同时setViewName(“show”) 这也是转发

作用:项目中存在视图解析器,但是要转发的页面没在view目录下,那么就转发不到
例如:转发和index.jsp同级目录的jsp文件 setViewName(“forward:/hello.jsp”)

2、redirect

处理器方法返回ModelAndView,实现重定向 redirect
语法:mv.setViewName(“redirect:/路由”)
特点:和上面的一样
• 框架对重定向的操作:框架会把ModelAndView中的简单类型的数据,转为字符串使用,作为hello.jsp的get请求参数使用,
• 在jsp中使用el表达式 ${param.xxxx} 来获取get请求参数值
• 目的:为了在重定向的过程中能够传递数据
缺点:
• 因为是重新从浏览器发出的请求,所以不能访问 WEB-INF 下的文件
• 重定向取不到请求作用域的数据。【不是同一个请求包了】

十三、统一全局异常处理

• 为了避免代码中,出现冗长的try..catch的语句。
• 统一全局异常处理:把controller中所有的异常都集中到一个地方,采用的是aop的思想,把业务逻辑和异常处理分开,解耦合。

1、使用两个注解

1. @ExceptionHandler
2. @ControllerAdvice

2、异常处理步骤

1. 新建一个maven web项目
2. 加入依赖
3. 新建一个自定义异常类,MyUserException ,在定义子类 NameException,AgeException
4. 在MyController中抛出异常  NameException,AgeException
5. 创建一个普通类,作为全局异常处理类
    • 在类的上面加入注解,@ControllerAdvice
    • 在类中定义方法,方法的上面加入 @ExceptionHandler
6. 创建处理异常的视图页面 【当发生异常了,让用户知道的页面】
7. 创建springmvc的配置文件
    • 组件扫描器,【注解创建对象 @Controller】
        • <context:component-scan base-package="com.yixuexi.controller"/>
    • 组件扫描器,【扫描@ControllerAdvice所在的包名】(直接扫描他的父包也行,那上面那个就免了)
        • <context:component-scan base-package="com.yixuexi.handler"/>
    • 声明注解驱动
        • <mvc:annotation-driven/>

不用写try catch,直接在方法的定义上抛出他的父类异常,让统一全局异常处理类代替你去处理异常

3、@ControllerAdvice

• 控制器增强(给控制器增加功能,---->异常处理功能)
• 特点:必须让框架知道这个注解所在的包名,需要在springmvc声明组件扫描器
• 位置:在类的上面定义

@ControllerAdvice
public class HandlerException {
    // 在这个统一全局异常处理类中写方法 来处理对应的异常
}

4、@ExceptionHandler(异常类.class)

• value参数表示该异常类由该方法进行处理,一个异常类的class
• 位置:方法定义的上面

@ExceptionHandler(NameException.class)
public ModelAndView doNameException(Exception e){}

统一全局异常处理类中的方法定义:和处理器方法定义是一样的,可以有ModelAndView,String void,等等返回值,也可以有多个参数
参数Exception e 表示controller类中抛出的异常对象,可以通过该形参获取详细的异常信息

@ExceptionHandler(NameException.class)
public ModelAndView doNameException(Exception e){
    ModelAndView mv = new ModelAndView();
    //给请求作用域中添加数据
    mv.addObject("msg","姓名必须是张三,其他不能显示");
    mv.addObject("ex",e);
    //转发给nameError页面【已经配置了视图解析器】
    mv.setViewName("nameError"); // 转发给nameError.jsp显示错误信息
    return mv;
}

5、发生异常之后的处理逻辑:

1. 需要把异常记录下来,记录到数据库,日志文件记录发生的时间,那个方法发生的,异常错误内容
2. 发送通知,把异常的信息通过邮件,短息,微信发送给相关人员
3. 给用户友好的提示

6、定义一个处理其他异常的方法(只能有一个该方法)

【其实统一都交给他处理就行,别的方法不需要】
• 因为处理的是Name和Age的异常,还会有许多不知道会发生什么的异常,比如空指针,类没找到,除数为0的异常….
• 方法的定义和上面的一样,特殊的是方法上定义的注解 value属性没有值

@ExceptionHandler(空的)
public ModelAndView doOtherException(Exception e){
    //抛出非 age 非 name异常时,在这里执行
    ModelAndView mv = new ModelAndView();
    mv.addObject("msg","未知异常");
    mv.addObject("ex",e);
    //转发给默认的defaultError页面
    mv.setViewName("defaultError");
    return mv;
}

十四、拦截器

1、拦截器是什么

1. 拦截器是springmvc的一种,需要实现HandlerInterceptor接口
2. 和过滤器类似,功能的方向侧重点不同:
    a. 过滤器是用来过滤请求参数,设置编码字符集等功能
    b. 拦截器是拦截用户的请求,对请求做判断处理的。
3. 拦截器特点:
    a. 全局的,可以对多个controller进行拦截
    b. 一个项目中可以有一个或者多个拦截器,他们在一起来拦截用户的请求
4. 拦截器常用在:
    a. 用户登陆处理,权限的检查,记录日志

2、拦截器的使用步骤

1. 定义类,实现HandlerInterceptor接口
    a. 实现里面的3个方法
2. 需要在springmvc配置文件中中声明拦截器,让框架知道拦截器的存在
    a. 指定拦截的请求的uri地址
拦截器的执行时间
    • 在请求处理之前,controller类中的方法执行之前,先被拦截
    • 在控制器方法执行之后,也会执行拦截器
    • 在请求处理完成后也会执行拦截器

拦截器看作是多个Controller中公用的功能,集中到拦截器统一处理,使用的aop的思想

3、拦截器和过滤器的区别

1. 过滤器是Servlet中的对象,拦截器是框架中的对象
2. 过滤器是实现Filter接口,拦截器是实现HandlerInterceptor
3. 过滤器是用来设置request response的参数,属性的,侧重对数据的过滤的
拦截器是用来验证请求的,能截断请求【返回false】
4. 过滤器是在拦截器之前 先执行的
5. 过滤器是tomcat服务器创建的对象,拦截器是springmvc创建的对象
6. 过滤器是一个执行时间点,拦截器有三个执行时间点
7. 过滤器可以处理jsp,js,html等等,

拦截器是侧重拦截对controller的请求,如果你的请求不能被中央调度器【DispatcherServlet】接收,那么他不会执行拦截器的内容

4、HandlerInterceptor接口中的三个方法

4.1、第一个 preHandle()

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    计算的业务逻辑,根据计算结果 返回true还是false
    return false;
}

preHandle:预处理方法,整个项目的入口,重要

形参:
    • 请求对象
    • 响应对象
    • handler:被拦截的控制器对象,controller对象
返回值boolean
    • true: 请求通过了拦截器的验证,可以执行处理器的方法
    • 同时拦截器的另外两个方法都会执行
    • false: 请求没有通过拦截器的验证,请求到达拦截器后,就截至了,请求不会被处理
特点:
    1. 方法在控制器方法(MyController的doSome()方法)之前先执行的
        • 用户的请求首先到达此方法
    2. 在这个方法中可以获取请求的信息,验证请求是否符合要求。
        • 可以验证用户是否登录,验证用户是否有权限访问某个链接地址(url)
        • 如果验证失败可以截断请求,请求不会被处理
        • 验证成功可以放行请求,此时控制器方法才能执行
    3. 可以想象成电影院的售票员,这个preHandle方法就是入口

4.2、第二个方法 postHandle()

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    可以在里面修正结果  modelAndView这个对象的方法
}

postHandle() 后处理方法

形参:
    • Handler:被拦截的处理器对象 MyController
    • modelAndView:处理方法的返回值
特点:
    • 在处理器方法之后执行的
    • 能够获取到处理器方法的返回值,ModelAndView
    • 可以修改ModelAndView中的数据和视图,影响最后的结果
作用:
    • 对原来的执行结果做二次修正

4.3、第三个方法

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

afterCompletion():最后执行的方法

形参:
    • Handler 被拦截的处理器对象
    • Exception ex:程序中发生的异常
特点:
    • 在请求处理完成后执行的。框架中规定当视图处理完成后【对视图进行了forward,就认为请求处理完成】
作用:
    • 一般做资源回收功能
    • 在程序中创建了一些对象,在这里进行删除。把占用的内存回收

十四、多个拦截器

声明拦截器:先在springmvc配置文件里声明的先执行,后声明的后执行(底层就是一个ArrayList)按照先后顺序放入到ArrayList

1、执行顺序:

两个拦截器的preHandle()方法返回值都是true

1111111111111-拦截器的 preHandle()方法执行
2222222222222-拦截器的 preHandle()方法执行
2222222222222-拦截器的 postHandle()方法执行
1111111111111-拦截器的 postHandle()方法执行
2222222222222-拦截器的afterCompletion()方法执行
1111111111111-拦截器的afterCompletion()方法执行

两个拦截器的preHandler()方法返回值 1是true 2是false

1111111111111-拦截器的 preHandle()方法执行
2222222222222-拦截器的 preHandle()方法执行
1111111111111-拦截器的 afterCompletion()方法执行

1返回是真的话 他的第三个方法 afterCompletion肯定会执行到
只要任意个返回false,那么controller里的doSome()方法不会执行


两个拦截器的preHandler()方法返回值 1是false 2是true

1111111111111-拦截器的 preHandle()方法执行

因为这个1在ArrayList集合中是第一个,他是false就直接是false了 后面的链条直接就截止了

十五、拦截器登陆验证

1. maven项目,加依赖
2. Web.xml注册中央调度器
3. 新建index.jsp发起请求
4. 新建MyController类处理请求
5. 创建MyController处理请求
6. 创建结果show.jsp
7. 创建login.jsp模拟登录(把用户的信息放到session中)
a. 创建logout.jsp模拟退出信息(把用户信息从session中删除)
8. 创建拦截器,从session中来获取用户的登录数据,验证能否访问系统
9. 创建一个验证的jsp,如果验证失败,给出提示
10. 创建springmvc的配置文件
Contents
  1. 1. SpringMVC
    1. 1.1. 一、SpringMVC是什么
    2. 1.2. 二、springMVC的工作模式
    3. 1.3. 三、SpringMVC入门案例
      1. 1.3.1. 1、创建maven项目,webapp
      2. 1.3.2. 2、加入依赖 spring-mvc 、servlet、
      3. 1.3.3. 3、在web.mxl文件中,注册springmvc框架的核心对象 DispatcherServlet
      4. 1.3.4. 4、创建发起请求的页面
      5. 1.3.5. 5、创建控制器类/后端控制器 @Controller
        1. 1.3.5.1. 1. 在类的上面加入@Controller注解,创建对象,放入到SpringMVC容器中
        2. 1.3.5.2. 2. 在中的方法上加入@RequestMapping注解
      6. 1.3.6. 6、创建springMVC的配置文件
        1. 1.3.6.1. 1. 声明组件扫描器,指定controller注解所在的包名
        2. 1.3.6.2. 2. 声明视图解析器,帮助开发人员设置视图文件的路径
        3. 1.3.6.3. 3. 注意:springmvc配置文件的名字要和web.xml文件中的这个属性中的值一致
      7. 1.3.7. 总结
    4. 1.4. 四、返回值ModelAndView对象使用
    5. 1.5. 五、SpringMVC web.xml 固定配置
    6. 1.6. 六、@RequestMapping注解
      1. 1.6.1. 1、属性:
      2. 1.6.2. 2、位置
    7. 1.7. 七、请求的处理流程
      1. 1.7.1. 1、springmvc请求的处理流程
      2. 1.7.2. 2、springmvc执行过程分析 init源码分析
        1. 1.7.2.1. 2.1 tomcat启动,创建容器的过程
      3. 1.7.3. 3、组件说明
    8. 1.8. 八、处理器方法的形参
      1. 1.8.1. 1、获取请求中携带的请求参数
        1. 1.8.1.1. 1.1 逐个获取
        2. 1.8.1.2. 1.2 对象接收
      2. 1.8.2. 2、解决请求中参数和方法形参不一致
        1. 1.8.2.1. 2.1 @RequsetParam注解:
    9. 1.9. 九、处理器方法的返回值
      1. 1.9.1. 1、返回ModelAndView
      2. 1.9.2. 2、返回String表示视图部分
      3. 1.9.3. 3、返回值void
      4. 1.9.4. 4、返回值Object 【处理AJAX】
        1. 1.9.4.1. ①、加入Json
        2. 1.9.4.2. ②、把java对象转换成json
      5. 1.9.5. 4、处理器方法返回一个String,并不是视图信息,而是数据
    10. 1.10. 十、解读url-pattern
      1. 1.10.1. 1、第一种处理静态资源无法访问的方式
      2. 1.10.2. 2、第二种处理静态资源无法访问的方式【常用】
    11. 1.11. 十一、路径问题
      1. 1.11.1. 1、地址分类:
      2. 1.11.2. 2、处理方案
      3. 1.11.3. 3、在项目中遇到了 / 开头的路径时,可加入${pageContext.request.contextPath}
      4. 1.11.4. 4、通过代码获取项目的路径,base可以直接使用获取到的
    12. 1.12. 十二、请求转发和重定向
      1. 1.12.1. 1、forward
      2. 1.12.2. 2、redirect
    13. 1.13. 十三、统一全局异常处理
      1. 1.13.1. 1、使用两个注解
      2. 1.13.2. 2、异常处理步骤
      3. 1.13.3. 3、@ControllerAdvice
      4. 1.13.4. 4、@ExceptionHandler(异常类.class)
      5. 1.13.5. 5、发生异常之后的处理逻辑:
      6. 1.13.6. 6、定义一个处理其他异常的方法(只能有一个该方法)
    14. 1.14. 十四、拦截器
      1. 1.14.1. 1、拦截器是什么
      2. 1.14.2. 2、拦截器的使用步骤
      3. 1.14.3. 3、拦截器和过滤器的区别
      4. 1.14.4. 4、HandlerInterceptor接口中的三个方法
        1. 1.14.4.1. 4.1、第一个 preHandle()
      5. 1.14.5. 4.2、第二个方法 postHandle()
      6. 1.14.6. 4.3、第三个方法
    15. 1.15. 十四、多个拦截器
      1. 1.15.1. 1、执行顺序:
    16. 1.16. 十五、拦截器登陆验证
|