文章目录

  • 1. SpringMVC的 拦截器
  • 1.1 拦截器和过滤器
  • 1.2 自定义拦截器
  • 1.3 SpringBoot 整合拦截器
  • 2. SpringMVC的上传文件
  • 2.1 前端上传文件方式
  • 2.2 后台接受方式
  • 3. SpringMVC的下载文件
  • 4. 补充
  • 4.1 " / "的作用在web.xml中
  • 4.2 Spring MVC不能使用基本数据类型!
  • 4.3 WEB-INF
  • 4.4 控制器走视图解析器的几个情况
  • 4.5 拦截器复习
  • 4.6 /\*是单层路径,/\*\*是多层路径
  • 5. 补充2
  • 5.1 bigint是对应java的long类型
  • 5.2 @RequestBody注解
  • 5.3 @RequestParamer注解作用
  • 5.4 接受参数的三种方式
  • 5.5 ModelAndView进一步解释
  • 6. SpringMVC统一异常处理的两种方式
  • 6.1 自定义类实现HandlerExceptionResolver接口
  • 6.2 @ControllerAdvice和@ExceptionHandler注解来统一处理SpringMVC异常(常用)
  • 7. SpringMVC的参数理解
  • 8. SSM整合 细节总结
  • 8.1 原生的Servlet 八大监听器
  • 8.2 Spring整合到web.xml文件中
  • 8.3 Spring读取外部文件,传到dataSource中
  • 8.4 事务管理器的作用
  • 9. \


1. SpringMVC的 拦截器

1.1 拦截器和过滤器


SpringMVC的处理器拦截器类似Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

过滤器是交给tomcat来操作的,而拦截器是通过spring来实现的。

过滤器和拦截器的区别:拦截器是AOP思想的具体应用。

springmvc 页面过滤特殊字符_mvc

1.2 自定义拦截器


想要自定义拦截器,必须实现HandlerInterceptor接口。

直接一点就是实现了HandlerInterceptor接口的类就是一个拦截器。

定义一个拦截器类MyInterceptor:

package com.itholmes.config;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

    //return true; 就是放行,执行下一个拦截器。
    //return false; 就是不放行,不执行下一个拦截器,就拒绝访问。
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("===========处理前===========");
        return false;//不放行
        //return true;//放行
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("===========处理后===========");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("===========清理===========");
    }
}

有了拦截器,就得在springmvc的配置文件里面注册一下:

<?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
       ">
    <!--1.注解驱动-->
    <mvc:annotation-driven/>
    <!--2.静态资源过滤,如果不配置我们的js文件加载不进去。-->
    <mvc:default-servlet-handler/>
    <!--3.扫描包-->
    <context:component-scan base-package="com.itholmes.controller"/>
    <!--4.视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--拦截器配置-->
    <mvc:interceptors>
		<!--第一类: 放到外面的拦截器bean是全局的!-->
		<bean class="com.itholmes.config.MyInterceptor"/>
        <mvc:interceptor>
            <!--
                这里的path就是拦截路径。
                    ?、/、/*和/**的区别配置:
                        "/index?"能够匹配到"/indexA","/indexB",可是不能匹配"/index",也不能匹配"/indexAA";请求

                        "/index*"能够匹配"/indexA","/indexAA",可是不能匹配"/index/A";index

                        "/index/*"能够匹配"/index/","/index/A","/index/AA","/index/ABC",可是不能匹配"/index",也不能匹配"/index/A/B";

                        "/index/**"能够匹配"/index/"下的多个子路径,好比"/index/A/B/C/D";
            -->
            <mvc:mapping path="/**"/>
            <!--第二类: 放到单独interceptor的拦截类bean是拦截部分的。-->
            <bean class="com.itholmes.config.MyInterceptor2"/>
        </mvc:interceptor>
    </mvc:interceptors>
</beans>

控制器类TestController :

package com.itholmes.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
    @GetMapping("/t1")
    public String test(){
        System.out.println("TestController==test方法执行了");
        return "OK";
    }
}

之后我们随便访问一个控制器,他就会显示这种效果。

springmvc 页面过滤特殊字符_springmvc 页面过滤特殊字符_02


?、/、/*和/**的区别配置:

  • “/index? :能够匹配到/indexA”,“/indexB”,可是不能匹配"/index",也不能匹配"/indexAA";请求
  • “/index* :能够匹配/indexA”,“/indexAA”,可是不能匹配"/index/A";index
  • “/index/* :能够匹配/index/”,“/index/A”,“/index/AA”,“/index/ABC”,可是不能匹配 “/index”,也不能匹配"/index/A/B";
  • “/index/**:能够匹配/index/“下的多个子路径,好比”/index/A/B/C/D”;

1.3 SpringBoot 整合拦截器


使用全注解的方式:

创建一个类使用@Configuration注解使他成为一个配置类,实现 WebMvcConfigurer接口,重写addInterceptors方法

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                //拦截的路径
                .addPathPatterns("/**")
                //放行的路径
                .excludePathPatterns("/login");
    }
}

2. SpringMVC的上传文件

2.1 前端上传文件方式


SpringMVC可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下它是不能处理文件上传工作。如果想让SpringMVC的文件上传功能,则需要在上下文中配置MultipartResolver。

multipart/form-data类型:这种编码方式会以二进制流的方式来处理表单数据。

springmvc 页面过滤特殊字符_java_03

2.2 后台接受方式


第一步:导入commons-fileupload和javax.servlet-api两个包。

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.4</version>
</dependency>
<!--Servlet-->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
</dependency>

第二步:配置springmvc的核心配置文件。

  • SpringMVC为文件上传提供了直接支持,这种支持是即插即用的MultipartResolver实现。
  • SpringMVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver。因此,SpringMVC文件上传还是需要依赖Apache COmmons FileUpload的组件!

springmvc 页面过滤特殊字符_java_04

在springmvc-config.xml文件中,配置CommonsMultipartResolver类的一个bean对象,注意这里的bean对象名字不能错误!因为在Spring中有类在用它!

<!--文件上传的位置-->
<!--这里的id必须是multipartResolver,因为在Spring中有类在用它!-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--请求的编码格式,必须和jsp的pageEncoding属性一直,以便正确读取表单的内容,默认为ISO-8859-1-->
    <property name="defaultEncoding" value="utf-8"/>
    <!--上传文件大小上限,单位为字节(10485760)=10M-->
    <property name="maxUploadSize" value="10485760"/>
    <property name="maxInMemorySize" value="40960"/>
</bean>

springmvc 页面过滤特殊字符_java_05


第三步:配置Controller文件。

第一种方式:IO读取。

package com.itholmes.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;

@RestController
public class FileController {

	//第一种方式:
    @RequestMapping("/upload")
    public String fileUpload(@RequestParam("file")CommonsMultipartFile file, HttpServletRequest request) throws IOException {

        //获取文件名:file.getOriginalFilename();
        String uploadFileName = file.getOriginalFilename();
        //如果文件名为空,直接回到首页。
        if("".equals(uploadFileName)){
            return "redirect:/index.jsp";
        }
        System.out.println("上传文件名:"+uploadFileName);


        //上传路径保存设置
        String path = request.getServletContext().getRealPath("/upload");
        //如果路径不存在,创建一个
        File readPath = new File(path);
        if(!readPath.exists()){
            readPath.mkdir();
        }
        System.out.println("上传文件保存地址:"+readPath);


        //获取文件流
        InputStream is = file.getInputStream();
        OutputStream os = new FileOutputStream(new File(readPath, uploadFileName));
        //读取写出
        int len = 0;
        byte[] buffer = new byte[1024];
        while ((len=is.read(buffer))!=-1){
            os.write(buffer,0,len);
            os.flush();
        }
        os.close();
        is.close();

        return "redirect:/index.jsp";
    }

}

第二种方式:直接写到文件中。

package com.itholmes.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;

@RestController
public class FileController {

    @RequestMapping("/upload2")
    public String fileUpload2(@RequestParam("file") CommonsMultipartFile file,HttpServletRequest request) throws IOException {
        //上传路径保存设置
        String path = request.getServletContext().getRealPath("/upload");
        File realPath = new File(path);
        if(!realPath.exists()){
            realPath.mkdir();
        }

        //上传文件地址
        System.out.println("上传文件保存地址:"+realPath);

        //通过CommonsMultipartFile的方法直接写文件
        file.transferTo(new File(realPath+"/"+file.getOriginalFilename()));

        return "redirect:/index.jsp";
    }

}

第四步:就直接测试就可以了。

  • 正常开发中,这些代码都是固定的格式,拿来即用!
  • 我们可以在target或out文件中能查看到。

3. SpringMVC的下载文件


文件下载步骤:

springmvc 页面过滤特殊字符_mvc_06

对应控制类写法:

package com.itholmes.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;

@RestController
public class FileController {

    @RequestMapping("/download")
    public String downloads(HttpServletResponse response,HttpServletRequest request) throws IOException {
        String path = request.getServletContext().getRealPath("/upload");
        String fileName = "项目.md";

        //1.设置response响应头
        response.reset();//设置页面不缓存,清空buffer
        response.setCharacterEncoding("utf-8");//设置字符编码
        response.setContentType("multipart/form-data");//二进制传输数据
        //设置响应头
        response.setHeader("Content-Disposition","attachment;fileName="+ URLEncoder.encode(fileName,"UTF-8"));

        File file = new File(path, fileName);
        //2.读取文件--输入流
        InputStream input = new FileInputStream(file);
        //3.写出文件--输出流
        OutputStream out = response.getOutputStream();

        byte[] buff = new byte[1024];
        int index = 0;
        while ((index=input.read(buff))!=-1){
            out.write(buff,0,index);
            out.flush();
        }
        out.close();
        input.close();
        return null;
    }

}

4. 补充


4.1 " / "的作用在web.xml中


/ 的作用就是来兜底(缺省)的!

servlet的 / 是兜底的效果,没有找到servleturl路径的时候就走它。

springmvc 页面过滤特殊字符_mvc_07

因此我们的前段控制器这只的url-pattern都是设置为 / ,目的就是不配置servlet,让请求们去访问呢去找前段控制器。

解释一下init-param的作用,就相当于我们代码中调用ClassPathXmlApplicationContext类的这个方法,并且传递了值。

springmvc 页面过滤特殊字符_spring_08

4.2 Spring MVC不能使用基本数据类型!


springmvc不能使用基本类型来接受参数。

原因很简单,当浏览器发送数据过来,但是没有有一个参数没有发送过来,例如:一个int类型的参数,SpringMVC会给它赋值一个null,这样就会报错,因为int类型默认是0,如果赋值null就会报错!

因此,我们使用他们的包装类就可以,因为包装类是对象,就可以赋值为null。

4.3 WEB-INF


web-inf 默认是对外资源不开放的!

4.4 控制器走视图解析器的几个情况


两种情况:

  • 当返回值为String的时候,会拿着返回的字符串走视图解析器。
  • 当无返回值或者返回值不为String的时候,会拿着当前的请求路径走视图解析器。

springmvc 页面过滤特殊字符_java_09

4.5 拦截器复习


springmvc 页面过滤特殊字符_spring_10


springmvc 页面过滤特殊字符_java_11


拦截器属于springmvc,而过滤器是拦截servlet。过滤器和springmvc同级的。简而言之,过滤器相当于拦截器的上级领导的同事。

4.6 /*是单层路径,/**是多层路径


/*是单层路径,/**是多层路径。

意思就是/*是包揽当前目录下的所有请求或页面。而/**是包揽了多层目录下的所有请求或页面。

5. 补充2

5.1 bigint是对应java的long类型


数据库汇总的biging类型应该对象到java的long类型,而不是int类型!!!

5.2 @RequestBody注解


@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的),所以只能发送POST请求。

GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交

5.3 @RequestParamer注解作用


springmvc 页面过滤特殊字符_springmvc 页面过滤特殊字符_12

这里的@RequestParam("empno1") Integer aa

相当于

String aa = request.getParameter("empno1")

5.4 接受参数的三种方式


下面三种方式默认form表单就是就可以:

  • @RequestParam只能接受form表单格式的数据。
  • 对于对象接受参数,也是默认form表单格式。

但是对于json格式只能发送post请求。

  • 想要接受json格式的参数必须使用@RequestBody注解,才能拿到对象中的数据。

@ResponseBody作用:将响应的数据直接放到响应体里面,不走视图解析器。

  • 对于返回值为字符串类型,就直接返回字符串。
  • 对于返回值为对象类型,就直接返回一个该对象类型的json字符串。

5.5 ModelAndView进一步解释


记住点:

  • ModelAndView就是把数据和页面放到一起了。
  • 就算使用了@ResponseBody,ModelAndView也会走视图解析器!!
  • ModelAndView是离不开JSP的!!!

6. SpringMVC统一异常处理的两种方式

6.1 自定义类实现HandlerExceptionResolver接口


这种方式是给客户端返回一个统一异常处理的页面。

解释一下resolveException的参数:

  • request和response参数就是请求和响应对象。
  • handler参数指明哪里出错。
  • ex参数错误的类型。
package com.itholmes.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

//记住这个类要被创建到spring容器中!
@Component
public class MyException implements HandlerExceptionResolver{

	public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
			Exception ex) {
		// TODO Auto-generated method stub
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("error"); // 这里走视图解析器拼接到error.jsp
		modelAndView.addObject("msg", "页面崩溃了");
		return modelAndView;
	}

}

因为这种方式返回值是ModelAndView,不管有没有@RequestBody注解都会去走视图解析器的!因此,它处理异常的方式是返回一个jsp页面到前段。

如果前段使用ajax来请求的就无法处理了。因此,这种方式不常用的!

6.2 @ControllerAdvice和@ExceptionHandler注解来统一处理SpringMVC异常(常用)


通过@ControllerAdvice类定义普通类和@ExceptionHandler注解标记异常方法,来实现SpringMVC的统一异常处理

  • @ExceptionHandler(异常的class) 注解很重要!
  • @ResponseStatus(HttpStatus.OK)可以设置http状态码。
package com.itholmes.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.itholmes.pojo.Result;

@ControllerAdvice
public class MyException{
	
	//这样这个方法就专门来处理空指针的异常
	@ExceptionHandler(NullPointerException.class)
	@ResponseBody//不走视图解析器,直接返回。
	@ResponseStatus(HttpStatus.OK)
	public Result myException(HttpServletRequest request, HttpServletResponse response, Object handler,
			Exception ex) {
		//与实现接口统一异常处理不同的是:这里的object不指定哪里报错了!
		Result result = new Result();
		result.setCode(0);
		result.setMsg("空指针异常");
		result.setData(ex);
		return result;
	}
	
}

7. SpringMVC的参数理解


SpringMVC中,注解的默认值:

  • 如果注解只有一个属性,那么肯定是赋值给该属性。
  • 如果注解有多个属性,而且前提是这多个属性都有默认值,那么你不写注解名赋值,注解先会查找一个名字为“value”这属性,然后赋值给他;如果value名的属性不存在,就会报错undefineded 属性名value。
  • 如果注解有多个属性,其中就有,没有设置默认值的属性,那么当你不写属性名进行赋值的时候,是会报错的。

8. SSM整合 细节总结

8.1 原生的Servlet 八大监听器


原生的Servlet是有八大监听器的。

springmvc 页面过滤特殊字符_springmvc 页面过滤特殊字符_13


每一个监听器,监听不同的功能。

8.2 Spring整合到web.xml文件中


先是Spring整合了mybatis。

后SpringMVC和Spirng(整合了mybatis) 将这两个再整合到context整个web容器中。

springmvc 页面过滤特殊字符_spring_14

上图的ContextLoaderListener监听器是Spring的监听器。让监听器来给我们创建一个classpathxmlApplicationContext,从而得到ioc容器。

8.3 Spring读取外部文件,传到dataSource中


springmvc 页面过滤特殊字符_mvc_15

8.4 事务管理器的作用


事务管理器就是来管理datasource的事务的。


springmvc 页面过滤特殊字符_springmvc_16

9. <mvc:view-controller>的使用


配置view-controller,直接把请求地址和视图名称关联起来,不必写handler(controller)方法了。

<!-- 配置view-controller,直接把请求地址和视图名称关联起来,不必写handler方法了。 -->
<!-- 
	@RequestMapping("/admin/to/login/page.html")
	public String testReceiveArrayTwo(ParamData paramData) {
		return "admin-login";
	}
	相当于上面这段代码。
-->
<mvc:view-controller path="/admin/to/login/page.html" view-name="admin-login"/>

10. DispatcherServlet的url-pattern:/ 和 /* 的区别


< url-pattern > / </ url-pattern > 不会匹配到*.jsp,即:*.jsp不会进入spring的 DispatcherServlet类 。

< url-pattern > /* </ url-pattern > 会匹配*.jsp,会出现返回jsp视图时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。