SpringMVC

    1.    SpringMVC-简介与Web前端框架特点
Spring MVC属于SpringFrameWork的后续产品
Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块
使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,
可以选择使用Spring的SpringMVC框架或集成其他MVC开发框架
Spring web mvc和Struts2都属于表现层的框架

Springmvc处理流程

    2.    SpringMVC-快速入门程序
1.创建web工程
2.导入springMVC相关jar包,在spring的基础上添加一个mvc的包    
3.添加配置文件
    springmvc.xml
        
            <?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"
                   xmlns:aop="http://www.springframework.org/schema/aop"
                   xmlns:tx="http://www.springframework.org/schema/tx"
                   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/aop
                http://www.springframework.org/schema/aop/spring-aop.xsd
                http://www.springframework.org/schema/mvc
                http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
                http://www.springframework.org/schema/tx
                http://www.springframework.org/schema/tx/spring-tx.xsd">    
            </beans>
4.配置前端控制器
    在web.xml当中配置前端控制器
        
             <!-- 配置SpringMVC前端控制器 -->
                <servlet>
                    <servlet-name>mySpringMVC</servlet-name>
                    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
                    <!-- 指定SpringMVC配置文件 -->
                    <!-- SpringMVC的配置文件的默认路径是/WEB-INF/${servlet-name}-servlet.xml -->
                    <init-param>
                        <param-name>contextConfigLocation</param-name>
                        <param-value>classpath:springmvc.xml</param-value>
                    </init-param>
                </servlet>
                <servlet-mapping>
                    <servlet-name>mySpringMVC</servlet-name>
                    <!-- 设置所有以action结尾的请求进入SpringMVC -->
                    <url-pattern>*.action</url-pattern>
                </servlet-mapping>
    springMVC中url-patten取值
/*  拦截所有   jsp  js png .css  真的全拦截.不建议使用
*.  action   *.do拦截以do action 结尾的请求
/   拦截所有,不包括jsp,包含.js .png.css     建议使用 
5.创建控制器
在src下面创建一个packeg com.itlike.springmvc
在下面创建一个Controller
@Controller
public class MyController {
    @RequestMapping("/first.action")
    public ModelAndView show(){
        //创建modelandview,用来存放数据和视图
        ModelAndView modelAndView=new ModelAndView();
        //请求过来后,界面跳转 往另外一个页面传一些数据
        //设置数据到模型中
        modelAndView.addObject("name","itlike");
        //设置视图jsp
        modelAndView.setViewName("/result.jsp");
        return modelAndView;
    }
}

6.在springMVC核心配置文件当中添加控制器扫描范围
由于使用的是注解的形式,需要在springmvc.xml下面添加配置注解扫描
    <!--注解扫描-->
    <context:component-scan base-package="com.itlike"/>

7.创建result.jsp
result.jsp
<body>
<h1>result----${name}</h1>
</body>

8.index.jsp页面跳转
  <body>
  <a href="${pageContext.request.contextPath}/first.action">发送请求-result.jsp</a>
  </body>

在idea中需要修改deployment 下面的application context 才能修改url地址

    3.    SpringMVC-执行流程
第一步进入index.jsp中,有一个链接
 <a href="${pageContext.request.contextPath}/first.action">发送请求-result.jsp</a>
点击这个连接,由于后缀是first.action,
由于在web.xml里配置了
指定了springmvc.xml的位置
    <servlet-mapping>
        <servlet-name>mySpringMVC</servlet-name>
        <!-- 设置所有以action结尾的请求进入SpringMVC -->
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>    
所以.action的后缀被controller拦截了.
下一步进行注解扫描
    <!--注解扫描-->
    <context:component-scan base-package="com.itlike"/>
然后使用MyController
由于/first.action index.jsp里超链接到这个结尾
所有MyController拦截到
        //设置数据到模型中
        modelAndView.addObject("name","itlike");
        //设置视图jsp
        modelAndView.setViewName("/result.jsp");
由这设置到链接地址为result.jsp,添加数据attributename为name,attributevalue为itlike.
在result.jsp中使用${name},取name中的value.
<h1>result----${name}</h1>

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

    5    SpringMVC-内部组件介绍
组件说明
DispatcherServlet
    前端控制器
    用户请求到达前端控制器,它就相当于mvc模式中的C
    dispatcherServlet是整个流程控制的中心
    由它调用其它组件处理用户的请求
    dispatcherServlet的存在降低了组件之间的耦合性
HandlerMapping
    处理器映射器
    HandlerMapping负责根据用户请求url找到Handler处理器
    springmvc提供了不同的映射器实现不同的映射方式
    HandlerMapping会把找到映射返回给前端控制器
Handler
    后端控制器
    在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
HandlerAdapter
    通过HandlerAdapter对处理器进行执行
    处理器适配器
ViewResolver
    视图解析器
    View Resolver负责将处理结果生成View视图
View
    springmvc框架提供了很多的View视图类型的支持,
    包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。

    6.    SpringMVC-视图解析器前后缀配置.
默认加载的组件
处理器映射器
    @RequestMapping:定义请求url到处理器功能方法的映射
    注解式处理器映射器,对类中标记了@ResquestMapping的方法进行映射。
    根据@ResquestMapping定义的url匹配@ResquestMapping标记的方法
    匹配成功返回HandlerMethod对象给前端控制器。
    HandlerMethod对象中封装url对应的方法Method。 
处理器适配器
    对标记@ResquestMapping的方法进行适配
    解析对应的方法
视图解析器
    视图解析器使用SpringMVC框架默认的InternalResourceViewResolver
    这个视图解析器支持JSP视图解析
    配置视图解析器
        当一个页面存放目录结构比较多时,就可以配置目录
        可以在返回地址上添加前缀和后缀
            
在springmvc.xml的bean中添加
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/myxq/"/>    //前缀
        <property name="suffix" value=".jsp"/>            //后缀
    </bean>
添加bean后,在Controller中
        //设置视图jsp
        modelAndView.setViewName("xxx");
设置视图就可以不添加前缀和后缀.

老版本之前:注册映射器和适配器
    3.2之前
    defaultAnnotationHandlerMapping
    AnnotationMethodHandlerAdapter
    <mvc:annotation-driven />

    7.    SpringMVC-请求转发
启动服务器加载SpringMVC
springmvc初始化
在web.xml中servlet下添加        <load-on-startup>,使SpringMVC前端控制器在初始化时加载.
    <!-- 配置SpringMVC前端控制器 -->
    <servlet>
        <servlet-name>mySpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 指定SpringMVC配置文件 -->
        <!-- SpringMVC的配置文件的默认路径是/WEB-INF/${servlet-name}-servlet.xml -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!--初始化加载-->
        <load-on-startup>1</load-on-startup>
    </servlet>
如果不使用初始化加载,那么在第一次使用时去初始化创建实例.

请求转发
在Controller层如果不使用ModelAndView去存储数据,可以直接返回一个String的值来实现跳转.
    @RequestMapping("/second.action")
    public String show2(){
        return "/result.jsp";
    }

    8.    SpringMVC-redirect重定向
重定向发送两次请求,请求转发发送一次请求.转发是服务器行为,重定向是客户端行为
    @RequestMapping("/second.action")
    public String show2(){
        return "redirect:/result.jsp";
    }

@Controller
public class MyController {
    //匹配请求可以去省略action
    @RequestMapping("/first")
    public ModelAndView show(){
        ModelAndView modelAndView = new ModelAndView();
        //请求过来后, 跳转到别一个界面   往别一个界面当中传一些数据
        modelAndView.addObject("name","itlike");
        modelAndView.setViewName("redirect:/second.action");//发送请求不可以去省略action
        return modelAndView;
    }
在@RequestMapping()里的.action可以省略,因为这是匹配请求.
但是setViewNmae里的.action不能省略,因为这是发送请求不能省略.


    9.    SpringMVC-使用原生request对象接收参数
接收参数
使用传统request对象接收参数    
Springmvc框架会自动把Request对象传递给方法。
页面传递参数  <a href="${pageContext.request.contextPath}/first?id=1">发送请求</a>
在控制器中获取参数
@Controller
public class MyController {
    @RequestMapping("/first")
    public String myform(HttpServletRequest request){
        String id = request.getParameter("id");
        System.out.println(id);
        return "/second.jsp";
    }
}

    10    SpringMVC-接收简单类型参数与@RequestParam
不使用request接收简单类型参数
当请求的参数名称和处理器形参名称一致时会将请求参数与形参进行绑定。
index.jsp
    <a href="${pageContext.request.contextPath}/second">发送第二个请求</a>
MyController
    @RequestMapping("/second")
    public String myform2(Integer id,String name){
        System.out.println(id);
        System.out.println(name);
        return "/second.jsp";
    }
需要保持和参数名称一致.
当不一致时.@RequestParam    
形参的类型与绑定的类型不一致时,可以使用@RequestParam进行匹配    
    //value传递的key值
    //默认required = true
    //defaultValue默认值
    public String myform2(@RequestParam(value = "id",required = false,defaultValue = "100")Integer idkey,
                          @RequestParam(value = "name",required = true,defaultValue = "PPAP")String names)
value    请求参数名字
required    是否必须,默认是true,表示请求中一定要有相应的参数,否则将报错
defaultValue    默认值,表示如果请求中没有同名参数时的默认值

    11.    SpringMVC-JavaBean接收参数
index.jsp
  <form action="${pageContext.request.contextPath}/myform">
      user:<input type="text" name="user_name"><br>
      age:<input type="password" name="user_age"><br>
      <input type="submit" value="提交">
  </form>
Controller层
    @RequestMapping("/myform")
    public String myform3(String user_name,String user_age){
        System.out.println(user_age);
        System.out.println(user_name);
        return "/second.jsp";
    }

创建一个User对象来保持form表单的数据
User中要求对象当中的属性要和表单当中的名称一致
添加的User中
    private String user_name;
    private String user_age;
添加set和get方法,再重写一个toString.
    //使用JavaBean接收参数
    @RequestMapping("/myform")
    public String myform3(User user){
        System.out.println(user);
        return "/second.jsp";
    }

    12.    SpringMVC-数组接收参数
数组接收数据
name相同时,中以使用数组来接收对应的参数
index.jsp里
  <hr>
  <form action="${pageContext.request.contextPath}/myform2">
      user:<input type="text" name="name"><br>
      age:<input type="text" name="name" ><br>
      <input type="submit" value="提交">
  </form>
Controller//接收数组
    @RequestMapping("/myform2")
    public String myform4(String name[]){
        System.out.println(Arrays.toString(name));
        return "second.jsp";
    }        
            
form表单有一个选择功能
  <hr>
  <form action="${pageContext.request.contextPath}/myform2">
      user:<input type="text" name="user_name"><br>
      age:<input type="password" name="user_age"><br>
      爱好:<input type="checkbox" name="hobby" value="篮球 ">篮球
      <input type="checkbox" name="hobby" value="乒乓球 ">乒乓球
      <input type="checkbox" name="hobby" value="足球 ">足球
      <input type="submit" value="提交">
  </form>
Controller接收
    @RequestMapping("/myform2")
    public String myform4(User user){
        System.out.println(user);
        return "second.jsp";
    }
在User类中添加    
private String hobby[];    //这个属性需要和jsp里的标签一样
添加set和get方法和toString

    13.    SpringMVC-包装类接收参数
添加一个Dog类,包含2个属性name,color.
添加他们的set get 和toString.
在User中添加private Dog dog,
添加get set 和tostring.
在index.jsp中添加
      宠物名称:<input type="text" name="dog.name"> <br>
      宠物颜色:<input type="text" name="dog.color"> <br>
Controller拦截接收.

    14.    SpringMVC-List集合接收参数
User中    private List<Dog> dogs;
set get toString.
index.jsp
      宠物名称:<input type="text" name="dogs[0].name"> <br>
      宠物颜色:<input type="text" name="dogs[0].color"> <br>
      <br>--------宠物---------<br>
      宠物名称:<input type="text" name="dogs[1].name"> <br>
      宠物颜色:<input type="text" name="dogs[1].color"> <br>

    15.    SpringMVC-参数类型转换器
@Controller
public class MyController2 {
    @RequestMapping("convert")
    public ModelAndView show(Integer age){
        System.out.println(age+1);
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.setViewName("/second.jsp");
        return modelAndView;
    }
}

convert.jsp
<form action="${pageContext.request.contextPath}/convert">
    年龄:<input type="text" name="age">
    <input type="submit" value="提交">
</form>

在JSP中输入的是String类型,
在ModelAndView中内置转换器可以转换为Integer类型

自定义参数绑定,根据业务需求自定义数据显示格式
修改商品日期
由于日期数据有很多种格式,springmvc没办法把字符串转换成日期类型。所以需要自定义参数绑定。
分析
前端控制器接收到请求后,找到注解形式的处理器适配器
对RequestMapping标记的方法进行适配,并对方法中的形参进行参数绑定。
内部已经定义了很多的转换器,比如可以直接使用int类型来接收字符串
日期类型与字符串比较特殊,字符串的日期格式,有很多种.可以自己来定义是哪种格式的转换
可以在springmvc处理器适配器上自定义转换器Converter进行参数绑定。

当使用日期类型时,输入可以使用1991/12/12,可以自动识别,但是其他不行.
如果不想使用/这种格式.
需要自定义一个转换器.

    16.    SpringMVC-自定义Converter类型转换器
第一步创建转换器DateConverter
public class DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
        try{
            if(null!=source){//2020:05-20 11_43-50
                DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
                return dateFormat.parse(source);
            }
        }catch (ParseException e){
            System.out.println("转换异常");
            e.printStackTrace();
        }
        return null;
    }
}


第二步在springMVC核心配置文件当中自定义转换器
    <!--配置Converter转换器 转换工厂-->
    <bean id="dataConverter" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <!--可以配置多个转换器-->
        <property name="converters">
            <list>
                <bean class="com.itlike.web.converter.DateConverter"/>
            </list>
        </property>
    </bean>
    <!--注解驱动-->
    <mvc:annotation-driven conversion-service="dataConverter"/>

Controller层
@Controller
public class MyController2 {
    @RequestMapping("convert")
    public ModelAndView show(Integer age, Date date){
        System.out.println(age);
        System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(date));
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.setViewName("/second.jsp");
        return modelAndView;
    }
}

    17.    SpringMVC-解决post请求中文乱码
当使用method="post"使用post方式提交时.当发送post请求时,带有中文的参数会发生乱码
解决办法.在web.xml当中添加一个过滤器
    <!-- 解决post乱码问题 -->
    <filter>
        <filter-name>encoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <!-- 设置编码参是UTF8 -->
        <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>
    18.    SpringMVC-@RequestMapping之Value属性.
Value属性,用来设置请求路径,值是一个字符串数组,可以设置多个路径共同访问对应方法
@Controller
public class MyController3 {
    @RequestMapping(value = {"testrequestmapping","testrequestmapping2"})    //可以匹配2个请求.
    public ModelAndView testquest(String id){
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.addObject("id",id);
        modelAndView.setViewName("/second.jsp");
        return modelAndView;
    }
}
requestmapping.jsp
<a href="${pageContext.request.contextPath}/testrequestmapping?id=1">请求方式1</a>
<a href="${pageContext.request.contextPath}/testrequestmapping2?id=2">请求方式2</a>
一个值value可以省略不写.
        
    19.    SpringMVC-@RequestMapping之Method属性
method属性,用来设置映射的请求方式 ,值是RequestMethod类型的数组
如果没有写,则没有限制,post与get都可以请求到对应的方法,
如果指定了请求类型,则必须得是相应的请求才能访问到对应的方法.
.jsp
<form action="${pageContext.request.contextPath}/testMethod" method="get">
    <input type="submit" value="测试method">
</form>
Controller
    @RequestMapping(value = {"testMethod"},method = {RequestMethod.GET,RequestMethod.POST})
    public ModelAndView test(){
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.setViewName("/second.jsp");
        return modelAndView;
    }

    20.    SpringMVC-@RequestMapping之params属性
params属性,必须设置对应的请求参数和请求值才能访问到对应的内容
.jsp
<a href="${pageContext.request.contextPath}/testparams?id=3&name=4">发送请求params</a>
Controller
    @RequestMapping(value = {"testparams"},
            method = {RequestMethod.GET,RequestMethod.POST},
            params = {"id=3","name!=5"})        //params属性必须满足才能访问
    public ModelAndView testparams(){
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.setViewName("/second.jsp");
        return modelAndView;
    }

    21.    SpringMVC-@RequestMapping之headers属性
headers属性,发送的请求头必须要与设置的请求相同时,才能够访问到对应的方法
<a href="${pageContext.request.contextPath}/testheaders?name=itlike&age=2">请求方式testheaders</a>

    @RequestMapping(
            value = "testheaders",
            headers = {"Host=localhost:8080","Referer=http://localhost:8080/requestmapping.jsp"}
    )

    22.    SpringMVC-@RequestMapping地址通配符写法
ant风格地址,Ant风格请求路径的一种匹配方法
?     一个?匹配一个字符               @RequestMapping("testant/?") .jsp里/testant/a 
                       @RequestMapping("testant/??")  .jsp里/testant/xs 
*     匹配任意字符               @RequestMapping("testant/*/itlike")    .jsp里/testant/xsasds/itlike
**    匹配多重路径    两个*表示任意级   @RequestMapping("testant/**/itlike")    .jsp里/testant/xsasds/asda/asdasd/itlike

    23.    SpringMVC-@PathVariable接收rest参数
rest风格,资源定位及资源操作的风格.不是协议,可以遵循,也可以不遵循

REST风格请求,REST 即 Representational State Transfer (资源)表现层状态转化.
用URL定位资源,用HTTP描述操作,是目前最流行的一种互联网软件架构.
它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用.
使用POST, DELETE, PUT, GET 分别对应 CRUD,Spring3.0 开始支持 REST 风格的请求.    

传统的操作资源
    http://localhost:8080/get.action?id=10        查询 get
    http://localhost:8080/add.action                        新增 post
    http://localhost:8080/update.action                   修改 post
    http://localhost:8080/delete.action?id=10          删除 post
restful操作资源
    http://localhost:8080/goods/1        查询GET
    http://localhost:8080/goods        新增POST
    http://localhost:8080/goods        更新PUT
    http://localhost:8080/goods/1        删除DELETE
.jsp
<a href="${pageContext.request.contextPath}/rest/1.action">请求方式rest</a>
Controller
    @RequestMapping(value = "rest/{id}",headers = {"Host=localhost:8080","Referer=http://localhost:8080/requestmapping.jsp"})
    public String rest(@PathVariable Integer id){
        System.out.println(id);
        return "/second.jsp";
    }

    24.    SpringMVC-发送PUT与DELETE请求
发送put与delete请求
默认情况下Form表单是不支持PUT请求和DELETE请求的
spring3.0添加了一个过滤器HiddenHttpMethodFilter
可以将post请求转换为PUT或DELETE请求
配置过滤器
    <!--HiddenHttpMethodFilter过滤器实现restful请求-->
    <filter>
        <filter-name>hiddenmethod</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>hiddenmethod</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
发送请求
<form action="${pageContext.request.contextPath}/testRestForm/2.action" method="post">
    <input type="hidden" name="_method" value="put">    //必须定义一个隐藏表单,name必须为_method,value为请求方式
    <input type="submit" value="测试RestForm">
</form>    
服务器接收处理
    @RequestMapping(value = "testRestForm/{id}",method = RequestMethod.PUT)
    public String restForm(@PathVariable String id){
        System.out.println("testRestForm"+id);
        return "redirect:/second.jsp";        //JSPs only permit GET POST or HEAD,使用重定向,而不是请求转发
    }
或者是
    @RequestMapping(value = "testRestForm/{id}",method = RequestMethod.PUT)
    public String restForm(@PathVariable String id){
        System.out.println("testRestForm"+id);
        return "redirect:/localsecond";
    }
    @RequestMapping("localsecond")
    public String localsecond(){
        return "/second.jsp";
    }

注入事项
从tomcat8开始,如果直接返回jsp页面,会报405错误  JSPs only permit GET POST or HEAD    
使用重定向的形式跳转到对应jsp
或者是直接把对应jsp的 isErrorPage="true"

    25.    SpringMVC-HiddenHttpMethodFilter源码分析


    26.    SpringMVC-@RequestHeader注解
作用在方法中接收请求头当中的信息
示例:
    @RequestMapping(value = "testHeader")
    public String testHeader( @RequestHeader("Referer")String referer, 
                  @RequestHeader("Host")String host){
        System.out.println(referer+"   "+host);
        return "/second.jsp";
    }
jsp
<a href="${pageContext.request.contextPath}/testHeader">获取头部</a>
Header里的所有参数都能获取.

    27.    SpringMVC-@CookieValue注解
作用用来接收浏览发送过来的cookes值 
可以使用@RequestHeader("Cookie"String cookie)来获取全部的cookie值.
示例:
    @RequestMapping(value = "testCookie")
    public String testCookie(@CookieValue("JSESSIONID")String sessionid){
        System.out.println(sessionid);
        return "/second.jsp";
    }

    28.    SpingMVC-传值方式Model和ModelAndView
使用ModelAndView的方式
请求页面index.jsp
  <a href="${pageContext.request.contextPath}/testModel">测试testModel</a>
控制器
@Controller
public class MyController {
    @RequestMapping(value = "testModel")
    public ModelAndView testModel(){
        ModelAndView modelAndView=new ModelAndView();
        //把数据写到request域
        modelAndView.addObject("name","itlike");
        modelAndView.setViewName("result.jsp");
        return modelAndView;
    }
}
跳转页面result.jsp
<h1>XXX---XXX-----${requestScope.name}</h1>
使用Model的方式
    @RequestMapping(value = "testModel")
    public String testModel(Model model){
     //把数据写到request域
        model.addAttribute("name","itlike000");
        return "/result.jsp";
    }
使用model不需要自己创建,都是写在request域中.
    
    29.    SpringMVC-Model方式AddAttribute
ModelMap
ModelMap对象主要用于传递控制方法处理数据到结果页面
也就是说我们把结果页面上需要的数据放到ModelMap对象中即可
request对象的setAttribute方法的作用: 用来在一个请求过程中传递处理的数据。 
使用方法与model一样

Model
Model 和 ModelMap 的实例都是spirng mvc框架来自动创建并作为控制器方法参数传入,用户无需自己创建
可以简单地将model的实现类理解成一个Map
Request级别的模型数据
Model 是一个接口, 其实现类为ExtendedModelMap,继承了ModelMap类
Model的方法
第一种addAttribute
Model addAttribute(String attributeName, Object attributeValue);    //添加键值属性对
model.addAttribute("name","itlike00");

第二种asMap
Map<String, Object> asMap();    //将当前的model转换成Map
    @RequestMapping(value = "testModel")
    public String testModel(Model model){
        //把数据写到request域
        model.addAttribute("name","itlike00");
        System.out.println(model.asMap());
        return "/result.jsp";
    }
直接使用model.asMap()  ,{name=itlike00}输出.保存为键值对的形式

第三种addAttribute
Model addAttribute(Object attributeValue);  //以属性的类型为key键,添加属性
    @RequestMapping(value = "testModel")
    public String testModel(Model model){
        //把数据写到request域
        model.addAttribute("name","itlike00");
        Goods goods1=new Goods();        //将类名的首字母改为小写 Goods-->goods当做key,和实例无关
        goods1.setName("goods1123");
        goods1.setPrice("1023");
        model.addAttribute(goods1);
        System.out.println(model.asMap());
        return "/result.jsp";
    }
<h1>XXX---XXX-----${goods.name}---${goods.price}</h1>
    30.    SpringMVC-Model方法AddAllAttribute
第四种
Model addAllAttributes(Map<String, ?> attributes);
将attributes中的内容复制到当前的model中,如果当前model存在相同内容,会被覆盖
有相同的key就会被覆盖.
        HashMap<String,Object> hashMap=new HashMap<>();
        hashMap.put("name","itlike it0002");
        hashMap.put("hot",1000);
        model.addAllAttributes(hashMap);
        System.out.println(model.asMap());
        return "/result.jsp";

第五种
Model addAllAttributes(Collection<?> attributeValues);
以集合中数据的类型做为key,
将所提供的Collection中的所有属性复制到这个Map中,
如果有同类型会存在覆盖现象    
        ArrayList<Object> arrayList=new ArrayList<>();
        arrayList.add("myxq");
        arrayList.add(100);
        arrayList.add("xxxx");    //这里由于myxq和xxxx都是String类型,所以后面一个xxxx将覆盖上面的myxq.
        model.addAllAttributes(arrayList);
        System.out.println(model.asMap());

第六种
Model mergeAttributes(Map<String, ?> attributes);
将attributes中的内容复制到当前的model中
如果当前model存在相同内容,不会被覆盖
        HashMap<String,Object> hashMap1=new HashMap<>();
        hashMap1.put("name","hashmap111");    //由于上面已经有了name类型所以不覆盖不录入.
        hashMap1.put("hot1",2000);        //由于没有hot1类型所以可以录入
        model.mergeAttributes(hashMap1);
        System.out.println(model.asMap());

第七种
 boolean containsAttribute(String attributeName);
        System.out.println(model.containsAttribute("hot"));
直接使用如果有这个参数就返回true,没有返回false.

    31.    SpringMVC-Map传值到页面
    @RequestMapping(value = "testMap")
    public String testMap(Map map){
        map.put("key1","value1");
        map.put("key2","value2");
        return "result.jsp";
也可以直接用map进行传值
在jsp页面获取<h1>${requestScope.key1}------${requestScope.key2}</h1>//通过requestScope域来获取.

    32.    SpringMVC-@SessionAttributes注解
将模型中的某个属性暂存到 HttpSession 中,以便多个请求之间可以共享这个属性
value 通过指定key将model数据放到session域当中

在controller层中.sessionAttributes标签使用在类最上面.
@Controller
//把model中key为name的值存到session中
@SessionAttributes("color")        //@SessionAttributes(value = {"color","user"})存储多个值的方式
public class MyController {
    @RequestMapping("testSession")
    public String testSession(Model model){
        //把数据存到request中
        model.addAttribute("name","itlike 999");
        model.addAttribute("color","white");
        return "result2.jsp";
    }
}
在jsp页面中
<h1>request---->${requestScope.name}</h1>
<h1>session---->${sessionScope.color}</h1>

type 把指定类型的模型数据放到session域当中 
@SessionAttributes(value = "color",types = String.class),使用types可以获取这个类的所有属性.

    33.    SpringMVC-@SessionAttribute注解
 使用@SessionAttribute来访问预先存在的全局会话属性
它是使用在方法里面.需要session里有name的值才能访问.
如果没有则会报错.
    @RequestMapping("testSession2")
    public String testSession2(@SessionAttribute("name") String name){
        System.out.println(name);
        return "result3.jsp";
    }

    34.    SpringMVC-@ModelAttribute修饰参数
1.修改处理方法的参数时,自动把该参数放到model当中
在方法定义上使用 @ModelAttribute 注解,Spring MVC 在调用目标处理方法前,
会先逐个调用在方法级上标注了@ModelAttribute 的方法。
请求页面
  <form action="${pageContext.request.contextPath}/testModelAttribute">
    名称:<input type="text" name="name"><br>
    价格:<input type="text" name="price"><br>
    <input type="submit" value="提交">
  </form>
Controller层
    @RequestMapping("testModelAttribute")
    //会自动把对应的模型存放在model中
    public String testModelAttribute(@ModelAttribute(value = "user") Goods goods, Model model){
        System.out.println(goods);
        System.out.println(model);
        System.out.println(model.asMap());
        return "result3.jsp";
    }
转到页面
<h1>${goods.name}</h1>
<h1>${user.price}</h1>
因为前面已经指定了名字为user,所以不使用默认的类名首字母小写来保存.
所以goods.name不显示,user.price显示.

    35.    SpringMVC-@ModelAttribute修饰方法.
//在对应的RequestMapping映射方法执行前自动调用
//并且会自动的model,提交传到这个方法
    @ModelAttribute
    public void testModelAttribute123(Model model){
        System.out.println("ModelAttribute执行了");
        model.addAttribute("name","信息");
        Goods goods123 =new Goods();
        goods123.setPrice("999000");
        goods123.setName("ModelAttribute设置");
        model.addAttribute("user",goods123);    //由于这里添加的key名为user
    }

    @RequestMapping("testModelAttribute")
    //会自动把对应的模型存放在model中        //设置Goods goods1的value为user,所以覆盖为index.xml里输入的form表单的值.
                        //如果说这个user和上面不同,就会保存2个model的值而不是覆盖.
    public String testModelAttribute(@ModelAttribute(value = "user") Goods goods1, Model model){
        System.out.println(goods1);
        System.out.println(model.asMap());
        return "result3.jsp";
    }
下面一个会获取输入的值去覆盖上面设置的值.

    36.    SpringMVC-@ModelAttribute注意点
当key相同时,并不是覆盖,而是替换了相同key里的value值.
里面有相同名称的会替换掉,没有相同名称的就保持不变.

但是如果是@SessionAttributes保存的model,则会被覆盖,而不是替换值.

@Controller
//把model中key为sessionGoodsKey的值存到session中
@SessionAttributes(value = "sessionGoodsKey")
public class MyController {
    @RequestMapping("testSession3")
    public String testSession3(Model model){
        Goods goods=new Goods();
        goods.setName("sessionGoodsName");
        goods.setPrice("sessionGoodsPrice");
        model.addAttribute("sessionGoodsKey",goods);
        return "result3.jsp";
    }

   @ModelAttribute
    public void testModelAttribute123(Model model){
        System.out.println("-----------------------------");
        System.out.println(model);
        System.out.println("ModelAttribute执行了");

        Goods goods = new Goods();
        goods.setPrice("ModelPrice");
        goods.setName("ModelName");
        goods.setHot("ModelHot");
        model.addAttribute("modelGoods",goods);

        Goods goods2 = new Goods();
        goods2.setPrice("ModelPrice");
        goods2.setName("ModelName");
        model.addAttribute("sessionGoodsKey",goods2);
    }
    @RequestMapping("testModelAttribute")
    //会自动把对应的模型存放在model中
    //使用SessionAttribute进行限制,必须在session中有"sessionGoodsKey"才能访问
    public String testModelAttribute(@SessionAttribute(value = "sessionGoodsKey") Goods sessionGoodsKey,    
                     @ModelAttribute (value = "modelGoods") Goods abc, Model model){
        System.out.println(abc);
        System.out.println(model.asMap());
        return "result3.jsp";
    }
}

    37.    SpringMVC-mvc-view-controller配置
第一步从浏览器学习接收参数
第二步前端控制器写数据到页面model
第三步通过requestScope来在jsp展示参数

在springmvc中,可以不使用requestMapping去添加控制器控制跳转.
而是在springmvc.xml里配置    <mvc:view-controller path="testView" view-name="/result.jsp"/>
index.jsp  页面添加<a href="${pageContext.request.contextPath}/testView"> 测试View</a>
result.jsp 页面     <h1>结果页---------</h1>

点击index的连接就能跳转到result页面

mvc:view-controller
当我们发送一个请求时,如果没有找到对应的mapping,则会对配置文件当中匹配mvc:view-controller.

    38.    SpringMVC-mvc-annotation-driven
当在.xml配置中使用了mvc:viwe-controller时,
需要添加<mvc:annotation-driven/>才能使用@RequestMapping.

<mvc:annotation-driven/> 是一种简写形式    //不添加.org.springframework.web.servlet.DispatcherServlet无法找到控制器并把请求分发到控制器。
会自动注册三个Bean,默认情况3个自动注册,如果使用了mvc:viwe-controller则只注册后两个,Mapping不自动注册.
RequestMappingHandlerMapping,
RequestMappingHandlerAdapter,
ExceptionHandlerExceptionResolver

并提供了:数据绑定支持,
@NumberFormatannotation支持,
@DateTimeFormat支持,
@Valid支持,读写XML的支持(JAXB),
读写JSON的支持(Jackson)。

    39.    SpringMVC-form标签基本使用
简介:在使用SpringMVC的时候我们可以使用Spring封装的一系列表单标签,这些标签都可以访问到ModelMap中的内容.

作用:
第一是它会自动的绑定来自Model中的一个属性值到当前form对应的实体对象.
第二是它支持我们在提交表单的时候使用除GET和POST之外的其他方法进行提交,包括DELETE和PUT等.

示例:
通过restful方式传参
index.jsp
  <hr>
  <a href="${pageContext.request.contextPath}/testUpdate/1">测试更新</a>
MyController
    @RequestMapping("testUpdate/{id}" )    //通过@PathVariable接收参数
    public String testUpdate(@PathVariable Integer id){
        System.out.println(id);
        User user=new User();
        user.setAge(10);
        user.setUsername("itlike");
        model.addAttribute("user",user);
        return "/result.jsp";        //注意返回值需要添加/才能访问到.
    }

在result.jsp页面引入标签库
<%@taglib uri="http://www.springframework.org/tags/form" prefix="fm" %>
<body>
    <h1>结果页---------</h1>
<fm:form modelAttribute="user">    //如果不指定modelAttribute="xxx"那么自动寻找command为key.例子如下1.
    <fm:input path="username"/> 
    <fm:input path="age"/>
</fm:form>
</body>
当编辑时, 跳转到form表单页,传统模式要在跳转前先到数据库查询数据,然后进行表单数据回显
使用form之前一定要保证有对应的bean,没有对应的bean时, 会自动以command为key到request域中查询,当找不到的时候, 会报异常

    40.SpringMVC-form-checkboxes标签使用
在result.jsp中添加
性别:<fm:radiobutton path="gender" value="1" label="男"/>
     <fm:radiobutton path="gender" value="0" label="女"/>
会显示一个单选框,gender的value=1时为男,为0时为女.

checkboxes标签使用:在MyController层
    @RequestMapping("testUpdate/{id}" )
    public String testUpdate(@PathVariable Integer id,
                             Model model){
        System.out.println(id);
        User user=new User();
        String[] hobby=new String[]{"篮球","足球"};    //使用一个数组来表示选择的
        user.setHobby(hobby);
        model.addAttribute("user",user);

        ArrayList<Object> arrayList= new ArrayList<>();    //使用一个arraylist来展示选项
        arrayList.add("篮球");
        arrayList.add("足球");
        arrayList.add("乒乓球");
        model.addAttribute("allhobby",arrayList);

        return "/result.jsp";
}
在result.jsp页面:展示
    爱好:<fm:checkboxes path="hobby" items="${allhobby}"/>    //从request域中选取allhobby.

修改输入内容
在result.jsp的form表单添加一个按钮和一个action跳转地址.
<fm:form modelAttribute="user" action="${pageContext.request.contextPath}/update2">
    <input type="submit" value="修改">
</fm:form>
在Controller中写一个mapping接收这个请求,因为类和user一样,所有直接使用参数User类接收.
    @RequestMapping("update2")
    public String update2(User user){
        System.out.println(user);
        return "/result2.jsp";
    }

    41.    SpringMVC-form-select标签使用.
在controller中添加宠物list
        ArrayList<Object> petList=new ArrayList<>();
        Pet pet1=new Pet();
        pet1.setId(1);
        pet1.setName("狗");

        Pet pet2=new Pet();
        pet2.setId(2);
        pet2.setName("猫");

        Pet pet3=new Pet();
        pet3.setId(3);
        pet3.setName("老虎");
        petList.add(pet1);
        petList.add(pet2);
        petList.add(pet3);
        model.addAttribute("petList",petList);

        user.setPet(pet2);
在result.jsp中
    宠物:<fm:select path="pet.id" items="${petList}" itemValue="id" itemLabel="name"/>添加
实现一个类似于复选框的功能
    42.    SpringMVC-服务器表单校验.
为什么后端要做表单的校验,如果只使用前端校验的话,如果浏览器把JS给禁用掉,就完了.
JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 6.0 中 
JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解
指定校验规则,并通过标准的验证接口对 Bean 进行验证

Hibernate Validator 
是 JSR 303 的一个参考实现,
除支持所有标准的校验注解外,它还支持以下的扩展注解

Bean Validation 中内置的约束
     @Null   被注释的元素必须为 null       
     @NotNull    被注释的元素必须不为 null       
     @AssertTrue     被注释的元素必须为 true       
     @AssertFalse    被注释的元素必须为 false       
     @Min(value)     被注释的元素必须是一个数字,其值必须大于等于指定的最小值       
     @Max(value)     被注释的元素必须是一个数字,其值必须小于等于指定的最大值       
    @DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值       
    @DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值       
    @Size(max=, min=)   被注释的元素的大小必须在指定的范围内       
    @Digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内       
    @Past   被注释的元素必须是一个过去的日期       
    @Future     被注释的元素必须是一个将来的日期       
    @Pattern(regex=,flag=)  被注释的元素必须符合指定的正则表达式       

Hibernate Validator 附加的额外约束
    @NotBlank(message =)   验证字符串非null,且长度必须大于0       
    @Email  被注释的元素必须是电子邮箱地址       
    @Length(min=,max=)  被注释的字符串的大小必须在指定的范围内       
    @NotEmpty   被注释的字符串的必须非空       
    @Range(min=,max=,message=)  被注释的元素必须在合适的范围内 

使用Hibernate-Validator导入jar包

使用:
1.添加相应的jar包,在配置文件当中写上<mvc:annotation-driven/>
2.在模型当中添加对应的校验规则
在User类里添加
    @NotNull    //不为空    @NotBlank(message = "请输入正确姓名")可以使用notblank不为空,且长度大于0.
    private String username;
    @Max(value = 200,message = "请输入合法年龄")    //最大值为200
    private Integer age;
    @Email(message = "请输入正确邮箱")        //正确邮箱地址
    private String email;
    @Pattern(regexp = "^1(3|4|5|7|8)\\d{9}",message = "请输入正确手机号")    //正则表达式第一位为1,第二位为3,4,5,7,8,剩余9位为0-9数字
    private String phone;

在处理器方法的入参标记@Valid注解即可
    @RequestMapping("update2")
    public String update2(@Valid User user, BindingResult result){
        System.out.println(user);
        List<FieldError> fieldErrors = result.getFieldErrors();    //使用一个list集合来保持信息
        for (FieldError fieldError : fieldErrors) {        //使用循环来遍历
            System.out.println(fieldError.getField()+":"+fieldError.getDefaultMessage());
        }
        return "/result2.jsp";
    }
idea快捷键Ctrl+Alt+V,可以引入变量。例如:new String(); 自动导入变量定义
输入iter自动写入一个超级循环,sout可以快速输入System.out.println.

    43.    SpringMVC-表单数据错误信息回显
错误信息页面回显
使用form标签
<fm:error path="username"/>

添加一个判断有无错误信息,通过result.getErrorCount()是否为0.    
如果为0,里面就没有错误信息.
//判断有没有错误信息
        if(result.getErrorCount()!=0) {
            List<FieldError> fieldErrors = result.getFieldErrors();
            for (FieldError fieldError : fieldErrors) {
                System.out.println(fieldError.getField() + ":" + fieldError.getDefaultMessage());
            }
        return "/result.jsp";    //由于前端页面获取的不是ajax异步,所以需要添加model来添加爱好和宠物的选项.
        }

在result.jsp页面添加错误信息,使用<fm:errors path="">使用和前面相同.
    姓名:<fm:input path="username"/> <fm:errors path="username" cssStyle="color: blue"/> <br>
    年龄:<fm:input path="age"/> <fm:errors path="age"/> <br>
还可以使用里面的cssStyle参数定义样式.


使用原始表单错误信息写到Model中
        if(result.getErrorCount()!=0) {
            List<FieldError> fieldErrors = result.getFieldErrors();
            for (FieldError fieldError : fieldErrors) {
                System.out.println(fieldError.getField() + ":" + fieldError.getDefaultMessage());
                model.addAttribute(fieldError.getField(),fieldError.getDefaultMessage());
            }
        return "/result.jsp";
        }
    System.out.println(user);
    return"result2.jsp"
}

 

    44.    SpringMVC-静态资源访问
访问静态资源:
在进行Spring MVC的配置时,通常我们会配置一个dispatcher servlet用于处理对应的URL
在设置url-pattern时可以设置三种形式:
1./*    拦截所有   jsp  js png .css  真的全拦截.不建议使用
2./    拦截所有,不包括jsp,包含.js .png.css     建议使用 
3.*.action   *.do    拦截以do action 结尾的请求

url-pattern为/时访问静态资源:
方式1-<mvc:default-servlet-handler/>    //看你是不是静态资源文件
在springmvc.xml里配置
如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。
由于使用SpringMVC前端控制器拦截了所有,不包括jsp,包含.js .png.css
所有需要将静态文件放行过去让服务器默认的servlet进行处理而不拦截.


方式2- 采用spring自带<mvc:resources>方法
配置
     <mvc:annotation-driven />
     <mvc:resources location="/img/" mapping="/img/**"/>   
     <mvc:resources location="/js/" mapping="/js/**"/>    
     <mvc:resources location="/css/" mapping="/css/**"/>  
描述
    location元素表示webapp目录下的static包下的所有文件;
    mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b;
    该配置的作用是:DispatcherServlet不会拦截以/static开头的所有请求路径,并当作静态资源
    交由Servlet处理。
同时使用?

    45.    SpringMVC-@ResponseBody返回json数据
概述    当前端使用Ajax发送请求时,服务器要以JSON的数据格式响应给浏览器
使用方式    @ResponseBody来实现;注解方式

@ResponseBody
1.添加json处理相关jar包    
2.在配置文件当中写上<mvc:annotation-driven/>
3.设置映射方法的返回值为@ResponseBody
    方式1-直接返回一个对象
在index.jsp层导入jquery,使用script发送一个AJAX请求
    <script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
  <hr>
  <input type="button" id="btn" value="请求JSON数据">
  <script>
    $(function () {
      $("#btn").click(function () {
        //发送AJAX请求
        $.post("${pageContext.request.contextPath}/getJson",function (data) {
          console.log(data);
        });
      })
    })
  </script>

在Controller层,接收post请求并且返回一个json格式使用@ResponseBody.
    //返回一个JSON格式
    @RequestMapping("getJson")
    @ResponseBody
    public User getJson(){
        User user = new User();
        user.setUsername("Json IT");
        user.setAge(18);
        return user;
    }
        
    方式2-返回一个List集合
  @RequestMapping("getJson")
    @ResponseBody
    public list<Uset> getJson(){
    ArrayList<> arrayList=new ArrayList<>();
    arrayList.add(user1);
    arrayList.add(user2);
        return arraylist;
    }

    方式3-返回一个Map集合
  @RequestMapping("getJson")
    @ResponseBody
    public Map<String,Object>getJson(){
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("name","ccccc");
        hashMap.put("list","arraylist");
        return hashMap;
    }    

    46.    SpringMVC-表单序列化
表单序列化:序列化方式
现在有如下一个表单.
<form id="myform">
    user:<input type="text" name="username"><br>
    age:<input type="text" name="age" ><br>
    爱好:<input type="checkbox" name="hobby" value="篮球"> 篮球
    <input type="checkbox" name="hobby" value="乒乓球"> 乒乓球
    <input type="checkbox" name="hobby" value="足球"> 足球
  </form>
  <input type="button" id="formbtn" value="发送form">
写一个javascript来获取
    $(function () {
      $("#formbtn").click(function () {
        // 获取表单当中所有的参数,发送给服务器
        var serialize = $("#myform").serialize();
        console.log(serialize);
      })
    })
在前端页面获取的字符串是以&来连接的全体数据.
username=renhao.chen&age=1234&hobby=%E7%AF%AE%E7%90%83



使用序列化代码.添加到index.jsp的script中
    (function($){
      $.fn.serializeJson=function(){
        var serializeObj={};
        var array=this.serializeArray();
        var str=this.serialize();
        $(array).each(function(){
          if(serializeObj[this.name]){
            if($.isArray(serializeObj[this.name])){
              serializeObj[this.name].push(this.value);
            }else{
              serializeObj[this.name]=[serializeObj[this.name],this.value];
            }
          }else{
            serializeObj[this.name]=this.value;
          }
        });
        return serializeObj;
      };
    })(jQuery);

    $(function () {
      $("#formbtn").click(function () {
        // 获取表单当中所有的参数,发送给服务器
        var serialize = $("#myform").serializeJson();    //注意这里需要使用serializeJson()而不是serialize()
        //username=renhao.chen&age=1234&hobby=%E7%AF%AE%E7%90%83
        console.log(serialize);
      })
    })
最终接收到的表单形式:
age: "1234"
hobby: (2) ["篮球", "乒乓球"]
username: "renhao.chen"
__proto__: Object

在Controller层接收使用user,可以接收单个的checkbox,不能接收多个checkbox数组对象
    @RequestMapping("formJson")
    @ResponseBody
    public String formJson(User user){
        System.out.println(user);
        return "success";
    }
需要将数组转换为json

    47.    SpringMVC-@RequestBody接收json参数
使用ajax异步接收
    $(function () {
      $("#formbtn").click(function () {
        // 获取表单当中所有的参数,发送给服务器
        var serialize = $("#myform").serializeJson();
        console.log(serialize);
        console.log(JSON.stringify(serialize));

        $.ajax({
          type:"post",
          url:"${pageContext.request.contextPath}/formJson",
          data:JSON.stringify(serialize),
          contentType:'application/json',
          success:function (data) {
        alert(data)
            console.log(data);
          }
        });
        
      })
    })
因为前面使用的contentType是application/json
在Controller层使用@RequestBody获取值
作用:
默认情况下我们发送的都是Content-Type: 不是application/x-www-form-urlencoded
直接使用@RequestParam接收参数
如果不是Content-Type: 不是application/x-www-form-urlencoded编码的内容,例如application/json, application/xml等;
需要使用@RequestBody接收

使用方法
发送Json参数
    $.ajax({
                  type:"post",
                  url:"${pageContext.request.contextPath}/formJson",
                  data:JSON.stringify(serialize2),
                  dataType:'json',
                  contentType:'application/json',
                  success:function (data) {
                      alert(data.responseText)
                  }
              });
在controller层
    @RequestMapping("formJson")
    @ResponseBody
    public String formJson(@RequestBody User user){    //使用@RequestBody添加在参数前.
        System.out.println(user);
        return "success";
    }

但是这个时候选择一个选项会出错,因为选择2个是一个数组的形式,选择一个是字符串.
需要在index.jsp中添加一个判断,如果serialize.hobby类型是一个字符串,那么将他设为一个数组.
    $(function () {
      $("#formbtn").click(function () {
        // 获取表单当中所有的参数,发送给服务器
        var serialize = $("#myform").serializeJson();
        console.log(serialize);
        console.log(JSON.stringify(serialize));

        if(typeof serialize.hobby=="string"){        //添加在这判断
          serialize.hobby=new Array(serialize.hobby);
        }
      })
    })

如果在$.ajax中添加一个
dataType:'json'        //那么从控制器返回的值必须是一个json值.不然就会报错.
          success:function (data) {
            alert("成功");
            console.log(data);
          },
          error:function (data) {
            alert("失败");
            console.log(data);
          }

    48.    SpringMVC-@RequestBody获取文件信息
index.jsp添加上传文件
  <form action="${pageContext.request.contextPath}/myform" method="post" enctype="multipart/form-data">
    <input type="file" name="myfile" content="UTF-8"><br>
    <input type="submit" value="提交">
  </form>
Controller层
    @RequestMapping("myform")
    public String myform(@RequestBody String body){
        System.out.println(body);
        return "result2.jsp";
    }

    49.    SpringMVC-视图解析器
视图解析器
    请求处理方法执行完成后,最终返回一个 ModelAndView 对象
    对于那些返回 String,View 或 ModeMap 等类型的处理方法
    Spring MVC 也会在内部将它们装配成一个 ModelAndView 对象
    它包含了逻辑名和模型对象的视图
    Spring MVC 借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP 
视图
    视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户
    视图对象由视图解析器负责实例化
    在org.springframework.web.servlet 包中定义了一个高度抽象的 View 接口
        
    常见实现类
        InternalResourceView
            将JSP或其它资源封装成一个视图
            是InternalResourceViewResoler默认使用的实现类

    50.    SpringMVC-执行流程源码分析    (存疑)
执行DispatcherServlet
    1.获取mapping映射
    2.获取适配器    
    3.调用处理器,执行映射方法,返回MV    
    4.处理转发页面    
    5.在方法内部渲染页面
    6.创建视图对象
    7.调用View对象渲染页面
    8.在render内部解析数据
    9.转发到jsp页面

    51.    SpringMVC-文件下载
index.xml添加文件  
<a href="${pageContext.request.contextPath}/download/微信图片_20190228155116.jpg">下载图片1</a>
<a href="${pageContext.request.contextPath}/download/新员工IT手册.png">下载图片2</a>
Controller层
    @RequestMapping("download/{filename:.+}")
    public String download(@PathVariable String filename){
        System.out.println(filename);
        return "success";
    }
springmvc.xml
    <!--配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"/>    //前缀
        <property name="suffix" value=".jsp"/>            //后缀
    </bean>
注意,这么写只能获取名字,不能获取文件的扩展名.需要在requestmapping后面加:.+

下载实现的controller
@Controller
public class MyController {
    @RequestMapping("download/{filename:.+}")
    public ResponseEntity download(@PathVariable String filename, HttpSession session)throws Exception{
        System.out.println(filename+"下载成功");
        //1.获取文件路径
        ServletContext servletContext = session.getServletContext();
        String realPath=servletContext.getRealPath("/download/"+filename);
        //2.把文件读到程序当中
        InputStream io=new FileInputStream(realPath);
        byte[] body=new byte[io.available()];
        io.read(body);
        //3.创建响应头
        HttpHeaders httpHeaders = new HttpHeaders();
        filename= URLEncoder.encode(filename,"UTF-8");  //文件名下载时设置中文编码
        httpHeaders.add("content-Disposition","attachment;filename="+filename);
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(body, httpHeaders, HttpStatus.OK);

        return responseEntity;
    }
}

    52.    SpringMVC-文件上传
概述
    Spring MVC 为文件上传提供了直接的支持
    是通过即插即用的 MultipartResolver 实现的
    MultipartResolver是一个接口
    Spring MVC 上下文中默认没有装配 MultipartResovler
    如果想使用 Spring 的文件上传功能
    就必须得要自己下载相关jar包
    自己到配置文件当中装配到springMVC当中
上传步骤
    1.导入相关jar包
    2.在springmvc配置文件当中装配MultipartResovler
springmvc.xml中配置
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--设置字符集编码-->
        <property name="defaultEncoding" value="UTF-8"/>
        <!--设置最大上传容量-->
        <property name="maxUploadSize" value="102400"/>
    </bean>
index.xml
  <form action="${pageContext.request.contextPath}/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file"><br>
    <input type="submit" value="上传">
  </form>

Controller层
    @RequestMapping("/upload")
    public String upload(@RequestParam("file") CommonsMultipartFile file,HttpSession session)throws Exception{
        System.out.println(file.getContentType());
        System.out.println(file.getOriginalFilename());     //获取文件名称
        System.out.println(file.getSize());
        System.out.println(file.getName());                 //获取文件属性名称

        //确定上传的路径
        ServletContext servletContext = session.getServletContext();
        String realPath = servletContext.getRealPath("/upload");
        //变成程序当中的路径
        File uploadPath = new File(realPath);
        if(!uploadPath.exists()){
            uploadPath.mkdirs();    //如果路径不存在,创建一个新的
        }
        //确认最终的路径 /文件夹/文件名  工程的名称/upload/java.png
        String fileName=file.getOriginalFilename();
        uploadPath =new File(uploadPath+"/"+fileName);  //拼接一个新的路径
        //开始上传
        file.transferTo(uploadPath);

        return "success";
    }
获取的对应信息
注意此处上传的路径是在out文件夹下的artifact
关键:!!通过修改tomcat服务器配置deployment下的output directory可以修改到web目录下,文件上传的地址也就变了


    53.    SpringMVC-WebUploader实现多文件上传
多文件上传
WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件
需要的css     webuploader.css
需要的js    jquery.min.js
        Uploader.swf
        webuploader.js

创建一个upload页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>WebUploader文件上传简单示例</title>
    <%--引入css样式--%>
    <link href="${pageContext.request.contextPath}/css/webuploader.css" rel="stylesheet" type="text/css"/>
    <script src="${pageContext.request.contextPath}/js/jquery.min.js" type="text/javascript"></script>
    <%--引入文件上传插件--%>
    <script type="text/javascript" src="${pageContext.request.contextPath}/js/webuploader.js"></script>
    <script type="text/javascript">
        $(function () {
            var $ = jQuery,
                $list = $('#fileList'),
                //优化retina, 在retina下这个值是2
                ratio = window.devicePixelRatio || 1,
                // 缩略图大小
                thumbnailWidth = 100 * ratio,
                thumbnailHeight = 100 * ratio,
                // Web Uploader实例uploader;
                // 初始化Web Uploader
                uploader = WebUploader.create({
                    // 自动上传。
                    auto: false,
                    // swf文件路径
                    swf: '${pageContext.request.contextPath}/js/Uploader.swf',
                    // 文件接收服务端。
                    server: '${pageContext.request.contextPath}/upload',    //调用还是controller层
                    fileVal: 'file',
                    threads: '30',      //同时运行30个线程传输
                    fileNumLimit: '10',   //文件总数量只能选择10个 
                    // 选择文件的按钮。可选。
                    pick: {
                        id: '#filePicker',  //选择文件的按钮
                        multiple: true        //允许可以同时选择多个图片
                    },
                    //图片质量,只有type为`image/jpeg`的时候才有效。
                    quality: 100,
                    //限制传输文件类型,accept可以不写 (用于显示文件类型筛选)
                    /* accept: {
                    title: 'Images',//描述
                    extensions: 'gif,jpg,jpeg,bmp,png,zip',//类型
                    mimeTypes: 'image/*'//mime类型
                   } */
                });

            // 当有文件添加进来的时候,创建img显示缩略图使用
            uploader.on('fileQueued', function (file) {
                var $li = $(
                    '<div id="' + file.id + '" class="file-item thumbnail">' +
                    '<img>' +
                    '<div class="info">' + file.name + '</div>' +
                    '</div>'
                    ),
                    $img = $li.find('img');
                // $list为容器jQuery实例
                $list.append($li);
                // 创建缩略图
                // 如果为非图片文件,可以不用调用此方法。
                // thumbnailWidth x thumbnailHeight 为 100 x 100
                uploader.makeThumb(file, function (error, src) {
                    if (error) {
                        $img.replaceWith('<span>不能预览</span>');
                        return;
                    }
                    $img.attr('src', src);
                }, thumbnailWidth, thumbnailHeight);
            });
            // 文件上传过程中创建进度条实时显示。   
            // uploadProgress事件:上传过程中触发,携带上传进度。
            // file文件对象 percentage传输进度 Number类型
            uploader.on('uploadProgress', function (file, percentage) {
                console.log(percentage);
            });
            // 文件上传成功时候触发,给item添加成功class,
            // 用样式标记上传成功。
            // file:文件对象,   
            // response:服务器返回数据
            uploader.on('uploadSuccess', function (file, response) {
                $('#' + file.id).addClass('upload-state-done');
                //console.info(response);
                $("#upInfo").html("<font color='red'>" + response._raw + "</font>");
            });
            // 文件上传失败
            // file:文件对象 ,
            // code:出错代码
            uploader.on('uploadError', function (file, code) {
                var $li = $('#' + file.id),
                    $error = $li.find('div.error');

                // 避免重复创建
                if (!$error.length) {
                    $error = $('<div class="error"></div>').appendTo($li);
                }
                $error.text('上传失败!');
            });

            // 不管成功或者失败,
            // 文件上传完成时触发。
            // file: 文件对象
            uploader.on('uploadComplete', function (file) {
                $('#' + file.id).find('.progress').remove();
            });
            //绑定提交事件
            $("#btn").click(function () {
                console.log("上传...");
                uploader.upload();   //执行手动提交
                console.log("上传成功");
            });
        });
    </script>
    <script>
        var contextpath = ${pageContext.request.contextPath};
    </script>
    <script type="text/javascript" src=""></script>
</head>
<body style="padding:10px">
<h3>多文件上传</h3>
<%--dom结构部分--%>
<div id="uploader-demo">
    <%--用来存放item--%>
    <div id="fileList" class="uploader-list"></div>
    <div id="upInfo"></div>
    <div id="filePicker">选择文件</div>
</div>
<input type="button" id="btn" value="开始上传">
</body>
</html>

    54.     SpringMVC-异常处理
概述
    Spring MVC 通过 HandlerExceptionResolver  处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。
    SpringMVC 提供的 HandlerExceptionResolver 的实现类
异常处理
    处理 Handler 中用 @ExceptionHandler 注解定义的方法。

实例
在index.jsp层
  <hr>
  <a href="${pageContext.request.contextPath}/exception">测试exception</a>
在controller层
    @RequestMapping("exception")
    public String exception(){
        int i=1/0;    //报错的地方
        return "success";
    }
    @ExceptionHandler(value = ArithmeticException.class)    //使用ExceptionHandler来捕获异常
    public String doexception(Exception ex){            //ArithmeticException捕获算数异常
        System.out.println(ex);
        return "error";            //由于Springmvc.xml里配置了地址只用返回一个error,在web-inf/view下面创建error.jsp
    }

最后报错会返回error页面,在控制台打印错误java.lang.ArithmeticException: / by zero.

@ExceptionHandler优先级,根据继承关系,找继承关系比较近的那一个
@ControllerAdvice ,如果在当前类中没有找到@ExceptionHanler,则会到@ControllerAdvice 中的@ExceptionHandler 注解方法
比如
@ControllerAdvice
public class ExceptionController {
    @ExceptionHandler(value = Exception.class)
    public String doException(Exception ex){
        System.out.println(ex.getMessage());
        System.out.println(ex);
        return "error";
    }
}

    55.    SpringMVC-国际化
概述实现中文与英文的切换
    SpringMVC  根据 Accept-Language 参数判断客户端的本地化类型
    当接受到请求时,SpringMVC 会在上下文中查找一个本地化解析器(LocalResolver),
    找到后使用它获取请求所对应的本地化类型信息。    

默认实现过程
    要先创建国际化的资源文件
    在resource下创建一个new Resource Bundle,添加Resource Bundle base name language
    点+号添加_en_US.properties和_zh_CN.properties.    //注意这里的两个不能随便修改,表示英文和中文
US.properties        CN.properties
welcome=welcome        welcome=欢迎
name=itlike        name=撩课

    添加配置文件
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> //注意id为messageSource
        <property name="basename" value="language"></property>    
    </bean>

    添加JSTL  jar包
jstl.jar
standard.jar

    在页面当中编写标签
index.jsp添加
  <hr>
  <a href="${pageContext.request.contextPath}/local">测试本地国际化</a>

添加local.jsp页面
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>local</h1>
<a href="?language=zh_CN"><fmt:message key="language.cn" /> </a>
<a href="?language=en_US"><fmt:message key="language.en" /> </a>
<hr>
<fmt:message key="welcome"/>
<fmt:message key="name" />
</body>
</html>

原理
如果没有显式定义本地化解析器
SpringMVC 会使用 AcceptHeaderLocaleResolver:根据 HTTP 请求头的 Accept-Language 参数确定本地化类型

 

    56.    SpringMVC-中英文切换    
添加springmvc.xml配置
    <!--配置session本地解析器-->
    <bean class="org.springframework.web.servlet.i18n.SessionLocaleResolver" id="localeResolver"></bean>
    <mvc:interceptors>
        <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
            <property name="paramName" value="language"/>
        </bean>
    </mvc:interceptors>
添加后可以切换中英文.        
            
    57.    SpringMVC-拦截器
概述
    Java 里的拦截器是动态拦截 action 调用的对象。
    可以Controller中的方法执行之前与执行之后, 及页面显示完毕后, 执行指定的方法
    自定义的拦截器必须实现HandlerInterceptor接口

方法介绍
    preHandle()
        在业务处理器处理请求之前被调用
    postHandle
        在业务处理器处理完请求后
    afterCompletion
        在 DispatcherServlet 完全处理完请求后被调用

实例
定义一个类MyFisrtInterceptor,继承于HandlerInterceptor
public class MyFisrtInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("开始执行前的preHandle拦截");
        return false;        //true放行,false不放行.
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("执行后的postHandle拦截");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("页面显示后的afterCompletion拦截");
    }
}
重写父类的三种方法perHandle,postHandle,afterCompletion.

在springmvc中配置参数
    <mvc:interceptors>
        <bean class="com.itlike.web.interceptor.MyFisrtInterceptor"></bean>
    </mvc:interceptors>
这个配置是拦截所有的请求.

    58.    SpringMVC-拦截指定请求
如果执行过程中出现异常,那么postHandle的处理器方法执行后的不调用.

拦截指定的请求在mvc:interceptors下面添加mvc:interceptor,在下面再添加mvc:mapping指定拦截路径/local
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/local"/>    //指定拦截路径
            <bean class="com.itlike.web.interceptor.MyFisrtInterceptor"></bean>        //指定拦截器
        </mvc:interceptor>
    </mvc:interceptors>

还有只有指定地址不拦截,其他都拦截
<mvc:exclude-mapping path="/xxx">     //除了xxx请求不拦截,其他都拦截.
需要练在mapping下使用

多个拦截器执行顺序,prehandle是按顺序执行,其他是按倒序执行.12 21 21

开始执行前的preHandle拦截
第二个拦截器执行前
第二个拦截器执行后
执行后的postHandle拦截
第二个拦截器界面生成后
页面显示后的afterCompletion拦截

 

转载于:https://www.cnblogs.com/cqbstyx/p/10767091.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值