绿色健康小清新

耐得住寂寞,守得住繁华

SpringMVC

SpringMVC

SpringMVC简介

  1. SpringMVC中重要组件

    • DispatcherServlet:前端控制器.接收所有请求(如果配置/不包含jsp)
    • HandlerMapping:解析请求格式.判断希望要执行哪个具体的方法
    • HandlerAdapter:负责调用具体的方法
    • ViewResolver:视图解析器,解析结果,准备跳转到具体的物理视图
  2. Spring容器与springMVC的关系

    • Spring容器和SpringMVC容器是父子容器
    • SpringMVC容器能够调用Spring容器的所有内容

环境搭建

  1. 导入jar包

    spring-webmvc.jar

  2. 在web.xml中配置前端控制器

    如果不配置<init-param>会在/WEB-INF/<servlet-name>-servlet.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:com/annotation/springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>
  3. 在src下新建springmvc.xml

    • 引入xmlns:mvc命名空间

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      <!--扫描注解-->
      <context:component-scan base-package="com.annotation.controller"></context:component-scan>
      <!--注解驱动-->
      <!--mvc.annotation.DefaultAnnotationHandlerMapping-->
      <!--mvc.annotation.AnnotationMethodHandlerAdapter-->
      <mvc:annotation-driven></mvc:annotation-driven>
      <!--静态资源-->
      <!-- <mvc:resources location="/js/" mapping="/js/*" ></mvc:resources>-->
      <mvc:resources mapping="/js/**/**" location="/js/"></mvc:resources>
      <mvc:resources mapping="/css/**" location="/css/"></mvc:resources>
      <mvc:resources mapping="/img/**" location="/img/"></mvc:resources>
    • 编写控制器类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      3.2编写控制器类
      @org.springframework.stereotype.Controller
      public class DemoController implements Controller {
      @RequestMapping("demo")
      public String Demo(){
      System.out.println("执行demo");
      return "/Annotation/main.jsp";
      }

      @Override
      public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
      return null;
      }
      }

过滤器(具体和拦截器一起看)

注意是/* :表示截取一切请求,而/表示截取Controller中url请求

  1. 在web.xml中配置字符编码filter

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!--一定要放在第一个-->
    <filter>
    <filter-name>encoding</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>
    </filter>

    <filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
  2. 配置隐藏方法过滤器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <filter>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>

    <filter-mapping>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>

传参

  1. 把内容写到方法(HandlerMethod)参数中,SpringMVC只要有这个内容就会注入内容 (也可以是对象,自动进行匹配。或者是Servlet得参数(Request或Response)

  2. 基本数据类型参数

    • 默认保证参数名称和请求传递的参数名相同

    • 如果请求参数名和方法参数名不同应使用@RequestParam(value="")

      1
      2
      3
      4
      5
      public String Demo(People peo,@RequestParam(value = "name1") String name,@RequestParam(value="age1") int age, HttpServletRequest request){
      System.out.println(peo+name+age);
      request.setAttribute("demo123","测试");
      return "/param/index.jsp";
      }
    • 如果方法参数是基本数据类型(不是封装类)可以通过注解 @RequestParam(defaultValue="")设置默认值

      没有参数时 400错误505错误

      1
      public String page(@RequestParam(defaultValue ="2") int pageSize,@RequestParam(defaultValue = "1") int pageNumber){
    • 强制要求必须有某个参数 @RequestParam(required="")

      1
      public String demo2(@RequestParam(required = true) String name){
  3. HandlerMethod中参数是对象类型

    请求参数名和对象中属性名对应(get/set 方法)

  4. 请求参数中包含多个同名参数的获取方法

    复选框传递的参数就是多个同名参数

    1
    @RequestParam(value = "hover") List<String> list){
  5. 请求参数中是对象或属性格式

    • jsp代码

      1
      姓名<input type="text" name="peo.name"/> 年龄<input type="text" name="peo.age"/>
    • 新建一个类

      1
      public class Demo { //    private People peo;
    • 控制器

      1
      public String demo5(Demo demo){
  6. 在请求参数中传递集合对象类型参数

    • jsp代码

      1
      姓名<input type="text" name="peo[0].name"/> 年龄<input type="text" name="peo[0].age"/>
    • 新建类

      1
      public class Demo {  private List<People> peo;
  7. restful传值方式

    • 简化jsp中参数编写格式

    • 在jsp中设定特定的格式

      1
      <a href="/SpringMVC/demo8/abc/123" >跳转3</a>
    • 在控制器中

      在@RequestMapping中一定要和请求格式对应

      {名称}中名称自定义名称

      @PathVariable获取@RequestMapping中获取内容,默认按照参数名称去寻找

      1
      @RequestMapping("demo8/{name1}/{id}")//名称可以任意取 public String demo8(@PathVariable(value = "name1") String name,@PathVariable int id){
  8. ant风格的请求路径

    • ? 单字符
    • *任意个字符(0或多个)
    • ** 任意目录
  9. REST风格 :软件编程风格

    • GET :查
    • POST :增
    • DELETE :删
    • PUT :改

普通浏览器 只支持get post方式 ;其他请求方式 如 delelte|put请求是通过 过滤器新加入的支持。

1
2
3
4
5
6
7
8
<form action="handler/testRest/1234" method="post">
<input type="hidden" name="_method" value="DELETE"/>
<input type="submit" value="删">
</form>

//注意:要使用DELETE和PUT必须在接下来要跳转的界面加isErrorPage="true"
//<%@ page contentType="text/html;charset=UTF-8;" language="java" pageEncoding="UTF-8" isErrorPage="true"%>
@RequestMapping(value = "shan",method =RequestMethod.DELET

注意:

  • 在超链接中只支持?方式,在get中action不能写参数(两种方式都不行)

  • 在post中action可以写参数,?和rest风格都可以,并且还可以通过表单传值

  1. 一些常用注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Controller()
    //@RequestMapping("")
    //@ControllerAdvice //配置全局化,可以将异常处理的类加上这个注解
    public class test{}
    @RequestMapping(value = "cha",method = RequestMethod.GET,headers="Accept=text/html",params = {"id=1"}) //还有consumes和produces
    @ResponseBody
    //@ExceptionHandler只在处理异常的方法上写
    public String select(int id,BindingResult result,@RequestParam(value = "age",required = false,defaultValue = "8") Integer age,@RequestHeader("Accept-Language") String accept,
    @CoRequwestokieValue("JSESSIONID") String c){ //还有一些session,request,modelAttribute,PathVariable

ControllerAdvice的用法(可以指定哪几个类或者包使用)

  1. 全局异常处理@ExceptionHandler

  2. 全局数据绑定

  3. 全局数据预处理@ModelAttribute

  4. 直接获取request和response

    1
    public String testServletAPI(HttpServletRequest  request,HttpServletResponse response) {
  5. 一般在一个方法中,返回类型为String,ModelAndView,以及使用@ResponseBody注解修饰可以传其他类型;

  6. 在参数中,可以从前端传来的参数或者对象自动进行匹配,或者是request和response,map,model,MapModel,用@CookieValue,@RequestHeader,@PathVariable,@RequestAttribute,@SessionAttribute,@ModelAttribute标识的参数(attribute也可不用注解自动匹配),还有BindingResult(处理格式),Exception(处理异常)

跳转方式

  1. 默认跳转方式请求转发

  2. 设置返回值字符串内容

    • 添加redirect:资源路径 重定向
    • 添加forward:资源路径或 省略forward: 转发(默认)
1
return "redirect:/param/index.jsp";

视图解析器

  1. SpringMV会提供默认的视图解析器

  2. 程序员自定义视图解析器

1
2
3
4
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
  1. 如果不希望执行视图解析器,在方法返回值前添加forward:或者redirect:

    <center></center>

MVC解析jsp时,会默认使用InternalResourceView,如果发现JSP中存在jstl语言,则自动转换成JstlView

<center></center>

  1. 国际化

    常见的资源文件命名: 基名_语言_地区.properties(也可以不管地区)

    base_ 或者i18n

    _如果基名_zh_HK没找到,回去基名_zh里找

    <center></center>

  • 创建资源文件
1
2
3
#中文要转为ascill码
resource.welcome=\u6b22\u8fce
resource.exist=\u9000\u51fa
  • 配置SpringMVC.xml,加载资源文件
1
2
3
4
5
6
7
<!--加载国际化资源文件
1.将这个类在程序加载时,加入SPringMVC:springmvc在启动时,会自动查找一个id=“messageSource”
2.如果配置了ResourceBundleMessageSource,则该类会在程序启动时介入
-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
  • 通过jstl使用国际化 jstl.jar 和standard.jar
  1. 不经过@Controller照样通过SpringMVC实现

    1
    2
    3
    4
    5
    <!--从jsp跳转到jsp,依然会经过springmvc,并且依然会被视图解析器解析-->
    <!--此后所有的请求都会首先来匹配path,@RequestMapping会失效。如果想共存,要加个注解-->
    <mvc:view-controller path="/testJsp2Jsp" view-name="success"/>
    <!--此配置是SpringMVC的基础配置,很多功能都需要通过该注解来完成-->
    <mvc:annotation-driven></mvc:annotation-driven>
  2. 在@Controller中默认是请求转发的方式,即forward。可以设置为重定向。一旦修改了,就会自动忽略视图解析器。

    1
    2
    3
    4
    5
    6
    @RequestMapping(value="welcome",method = RequestMethod.GET,params={"name=zs","age!=23"},headers = "Accept=text/html")
    public String welcome(){
    //默认是请求转发forward;可以改为重定向,加个redirect:
    //并且加了前缀就会忽略配置的视图解析器
    return "success";
    }
  3. 处理静态资源

    解决静态资源方案:如果有springmvc对应的@requestMapping则交给spring处理;如果没有对应@requestMapping,则交给服务器tomcat默认的servlet去处理 :实现方法,只需要增加2个注解即可 springmvc.xml:

    1
    2
    3
    <!--该注解是SpringMVC的基础配置:接受一个请求,并且该请求没有对应的@RequestMapping,则该请求交给服务器默认的servlet去处理(直接访问)-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>
    <mvc:annotation-driven></mvc:annotation-driven>

@ResponseBody

  1. 在方法上只有@ResponseMapping时,无论方法返回值是什么认为需要跳转

  2. 在方法上添加@ResponseBody(恒不跳转)

    • 如果返回值满足key-value形式(对象或map)
      • 把对应响应头设置为application/json;charset=utf-8
      • 把转换后的内容以输出流的形式响应给客户端
    • 如果返回值类型不满足key-value.例如返回值为String
      • 把响应头设置为text/html(不用配置,默认会用这个进行处理)
      • 把方法返回值以流的形式直接输出

@responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据。

注意:在使用此注解之后不会再走视图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。一般配合ajax使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$(document).ready(function () {
//通过ajax请求springmvc
$("#testAjaxJson").click(function(){
$.post(
"/SpringMVC2/testJson" , //服务器地址
// {"name":"zs"} //请求的参数
function (result) { //回调函数,获得List<Student>,加上responseBody后,获得一个json数组
//eval(result)
for(var i=0;i<result.length;i++ ){
alert(result[i].age+" "+result[i].name);
}
}
);
})
}
);

@RequestMapping(value="demo12")
@ResponseBody
public People demo12() throws IOException {
People people=new People();
people.setName("张三");
people.setAge(12);
return people;
}

@RequestMapping(value="demo13",produces = "text/html;charset=utf-8")
@ResponseBody
public String demo13() throws IOException {
String str="hahahhah";
return str;
}

SpringMVC作用域传值的几种方式

  1. 使用原生servlet

    在HandlerMethod参数中添加作用域对象

  2. 使用map集合

    把map中内容放在request作用域中

    spring会对map集合通过BindingAwareModelMap进行实例化

  3. 使用SpringMVC中的model接口

    把内容最终放入到request作用域里

  4. 使用SpringMVC中ModelAndView类

    放在request作用域中

  5. 使用ModelMap

  6. 使用注解 @SessionAttributes、@RequestlAttribute (注意@ModelAttribute)

类型转换器(配置和数据格式化部分重叠)

  1. springmvc自带一些常见的类型转换器

    public String test(String id),即可以接受Stirng类型也可以接受int类型

  2. 可以自定义类型转换器

1
2
3
4
5
6
7
8
9
10
import org.springframework.core.convert.converter.Converter;
public class MyConverter implements Converter<String, Student> {
@Override
public Student convert(String s) {//s:2-zs
//接受前端传来的String
String[] studentStrArr=s.split("-");
Student student=new Student(Integer.parseInt(studentStrArr[0]),studentStrArr[1]);
return student;
}
}
1
2
3
4
5
6
7
8
9
10
11
<!--1.自定义转换器纳入SpringMVC容器-->
<bean id="myConverter" class="com.yanqun1.MyConverter"></bean>
<!--2.将myConverter再纳入SpringMVC提供的转换器Bea,可以直接使用FormattingConversionServiceFactoryBean-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myConverter"/>
</set>
</property>
</bean>
<!--3.将conversionFactory注册到annotation-driver中-->

数据格式化

1
2
3
4
5
@NumberFormat(pattern = "###,#")
private int age;

@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
1
2
<!--配置数据格式化注解和所依赖的bean,既可以实现数据格式化,又可以实现类型转换-->
<bean id="conversionService" class="org.springframework.format.support.Formattin)gConversionServiceFactoryBean"></bean>

BindingResult的使用(一定要放在后一个参数,并且注意和ModelAttribute一起使用的问题)

在Handler中,如果一个RequestMapping的方法参数第一个没有进行匹配成功,会由后面的参数进行匹配,有时可以使用BindingResult接受错误的信息

数据校验

  • JSR303
  • Hibernate Validator

使用Hibernate Validator步骤:

  1. 下载jar包(注意各个jar之间可能存在版本不兼容)

    • hibernate-validator-5.0.0.CR2.jar
    • classmate-0.8.0.jar
    • jboss-logging-3.1.1.GA.jar
    • validation-api-1.1.0.CR1.jar
    • hibernate-validator-annotation-processor-5.0.0.CR2.jar
  2. 在xml文件中写<mvc:annotation-driven>

  3. 作用:要实现Hibenate Validator/JSP303,必须实现SpringMVC的一个接口:ValidatorFactory。<mvc:annotation-driven></mvc:annotation-driven>会在springmvc容器中 自动加载一个LocalValidatorFactoryBean类,因此可以直接实现数据校验。

<center></center>

<center></center>

文件下载

三种方式(直接访问,inline,attachment.其中直接访问和inline受类型影响)

  1. 访问资源时响应头如果没有设置Content-Disposition,浏览器默认按照inline值进行处理inline能显示就显示,不能显示就下载

  2. 只需要修改响应头中Content-Disposition=“attachment;filename=文件名”

    • attachment下载,以附件形式下载.
    • filename=值就是下载时显示的下载文件名
  3. 实现步骤

    • 导入两个jar包 commons-io

    • 在jsp中添加超链接,设置要下载文件(一般不需要)

      在sprinmvc中放行静态资源files文件夹

    • 编写控制器方法

文件上传

  1. 基于apache的commons-fileupload.jar完成文件下载

  2. MuiltipartResovler作用

    • 把客户端上传的文件流转换为MuilpartFile封装类
    • 通过MuilpartFile封装类获取到文件流
  3. 表单数据类型的分类(提交为post的话,提交上限为2GB,get为2kb)

    • 在form的entype属性控制表单的类型
    • 默认值:application/x-www-form-urlencoded,普通表单数据(上传少量文字信息)
    • text/plain 大文字量时使用的类型,邮件,论文
    • muitipart/form-data 表单中包含二进制文件内容
  4. 实现步骤

    • 导入两个jar包commons-io和commons-fileupload

    • 编写jsp代码

    • 配置springmvc.xml

    • 编写控制器类

      MultipartFile对象名必须和表单里的属性名相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--配置文件上传解析器-->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<!--如果是-1表示无限制-->
<property name="maxUploadSize" value="102400"></property>
<property name="defaultEncoding" value="utf-8"></property>
</bean>

@RequestMapping("testUpload")
public String testUpload(String desc, MultipartFile file, HttpServletRequest request) {
String fileName = file.getOriginalFilename();
String proffix = fileName.substring(fileName.lastIndexOf("."));
String suffix = UUID.randomUUID().toString();
String filename=suffix+proffix;
try {
FileUtils.copyInputStreamToFile(file.getInputStream(),new File("D:\\workspace\\SpringMVC2\\web\\img",filename));
System.out.println(request.getServletContext().getRealPath("img"));
} catch (IOException e) {
e.printStackTrace();
}
return "redirect: /SpringMVC2/view/start.jsp";
}

配置拦截器

<center></center>

<center></center>

  1. Filter需要在web.xml中配置,依赖于Servlet;

  2. Interceptor需要在SpringMVC中配置,依赖于框架;

  3. Filter的执行顺序在Interceptor之前,具体的流程见上图;

  4. 两者的本质区别:拦截器(Interceptor)是基于Java的反射机制,而过滤器(Filter)是基于函数回调。从灵活性上说拦截器功能更强大些,Filter能做的事情,都能做,而且可以在请求前,请求后执行,比较灵活。Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验(比较泛的,比如登录不登录之类),太细的话,还是建议用interceptor。不过还是根据不同情况选择合适的。

  5. 实现HandlerInterceptor接口

  6. 在SpringMVC.xml中进行配置(注意顺序不能乱)

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--配置拦截器-->
<mvc:interceptors>
<!--拦截全部-->
<!-- <bean class="com.yanqun1.Interceptor.MyInterceptor"></bean>-->
<!--拦截指定的-->
<mvc:interceptor>
<!--指定拦截的路径-->
<mvc:mapping path="/**"/>
<!--指定不拦截的路径-->
<mvc:exclude-mapping path="/testBody"/>
<bean class="com.yanqun1.Interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>

异常处理

  1. 方式一

    SpringMVC: HandlerExceptionResolver接口,该接口的每个实现类 都是异常的一种处理方式:

  2. 方式二

    Exception:HandlerExceptionResolver: 主要提供了@ExceptionHandler注解,并通过该注解处理异常

1
2
3
4
5
6
7
8
//该方法 可以捕获本类中  抛出的ArithmeticException,ArrayIndexOutOfBoundsException异常
@ExceptionHandler({ArithmeticException.class,ArrayIndexOutOfBoundsException.class})
public ModelAndView handlerArithmeticException(Exception e){
System.out.println(e);
ModelAndView modelAndView=new ModelAndView("error");
modelAndView.addObject("error",e);
return modelAndView;
}

异常处理路径:最短优先

如果有方法抛出一个ArithmeticException异常,而该类中 有2个对应的异常处理法你发:

@ExceptionHandler默认只能捕获 当前类中的异常方法。

如果发生异常的方法 和处理异常的方法 不在同一个类中:@ControllerAdvice

ControllerAdvice的用法:

  1. 全局异常处理
  2. 全局数据绑定
  3. 全局数据预处理

总结:

  • 如果一个方法用于处理异常,并且只处理当前类中的异常:@ExceptionHandler

  • 如果一个方法用于处理异常,并且处理所有类中的异常: 类前加@ControllerAdvice、 处理异常的方法前加@ExceptionHandler

  1. 方式三

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <!--通过配置的方式处理异常-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <!--如果发生异常,异常对象会被保存在exceptionArrribute的value值中,并且会放入request域中-->
    <!--如果不写,默认就是exception-->
    <property name="exceptionAttribute" value="exception"></property>
    <property name="exceptionMappings">
    <props>
    <prop key="java.lang.ArithmeticException">
    error
    </prop>
    <prop key="java.lang.ArrayIndexOutOfBoundsException">
    error
    </prop>
    </props>
    </property>
    </bean>

自定义异常

@ResponseStatus

  1. 创建异常类

    1
    2
    3
    @ResponseStatus(value = HttpStatus.BAD_REQUEST,reason = "值不符合标准")
    public class NotEqualException extends RuntimeException{
    }
  2. 创建异常方法

    1
    2
    3
    4
    5
    6
    7
    8
    @Controller
    public class NotEqualMethodException {
    @RequestMapping("testNotEqualMethodException")
    @ResponseStatus(value = HttpStatus.BAD_REQUEST,reason = "值不符合标准")
    public String NotEqualMethodException (){
    return "success";
    }
    }
-------------本文结束感谢您的阅读-------------
六经蕴籍胸中久,一剑十年磨在手

欢迎关注我的其它发布渠道