springmvc 从入门到总结

来源:互联网 发布:靠谱代购淘宝店 知乎 编辑:程序博客网 时间:2024/05/19 21:17

springMvc的总结:(推荐,总共有十五章)

http://www.cnblogs.com/liukemng/p/3751338.html

框架

拦截器不拦截静态资源

http://www.cnblogs.com/banning/p/6195072.html

Spring

学习版本: 4.3.0

框架认识

框架学起来比较简单

但也有难的地方,难是难在底层原理

 

用了框架之后,写代码就非常简单,因为框架会完成一部分代码,

我们只要按框架的规则去使用就可以了

 

学习框架的方法:

与学习初级基础有所不同,

基础学习都是学习基本语法,完成简单的案例,逐步理解面向对象的编程思想.

框架属于中高级的学习,要运用面向对象的进行编程,接口编程

能够自已完成业务.熟悉业务.能够架构一个项目,属性框架的原理

 

框架学习程度:

相用框架

理解框架原理、走源码

自己编写框架部分

框架的由来

Md1

Md2

Jsp/servlet 的 mvc回顾

 

当一个方法中有部分代码在不断重复时,抽取出来做一个方法

当很多类在操作同一段代码时,抽出来做一个类

当很多类在做同一类事情的时候,抽出来做一个jar包或做成框架

 

这就是框架

框架,替程序员完成一部分代码,从而提高开发效率

框架就是一个模板,

Web应用的框架:webwork,jsf, struts1, struts2,springmvc

 

Mvc框架的工作

Servlet:

将页面请求映射到java类,也就是后台

接收并处理页面提交的数据

调用业务逻辑方法处理业务结果,将数据封装准备渲染到页面

控制页面跳转

 

Mvc的V层:

将页面请求映射到java类,也就是后台

获取并封装好页面提交的数据

渲染数据到页面

控制页面跳转  

 

 

Spring下载

http://repo.springsource.org/libs-release-local/org/springframework/spring

 

向下拉选中需要下载的版本。

 

点击相应需要下载的zip,window版本直接下zip即可

 

Spring mvc

Spring mvc是一个轻量级的基于请求响应的mvc框架。Mvc框架一般都是基于请求响应的(JSF是基于事件驱动的框架)。

Spring mvc的优势:

1. 性能较struts2好(struts2是快速开发)

2. Spring mvc使用简单,配置便捷,易上手

3. 天生与spring无缝集成(使用spring的IOC和AOP)(struts2也有可以与spring集成,但是需要插件需要配置)

4. 使用约定大于配置(只要遵守spring mvc的配置约定,那么编码非常简结)

5. 能进行简单的junit测试

6. 支持restful风格

7. 异常处理

8. 本地化、国际化、数据验证、类型转换等等

9. 拦截器

使用的人多,使用的公司多  

  

 

Spring mvc 简单的结构流程图

 

 

 

 

 

 

Springmvc工作流程描述

      1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;

      2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象

      (包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;

      3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法

      4.  提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

      HttpMessageConveter:将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息

      数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

      数据格式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等

      数据验证验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中

      5.  Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;

      6.  根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;

      7. ViewResolver 结合Model和View,来渲染视图

      8. 将渲染结果返回给客户端。

Hello spring mvc配置开发

1. 导入jar

commons-logging-1.1.3.jar

jstl-2.4.jar

servlet-api.jar

spring-beans-4.3.0.RELEASE.jar

spring-context-4.3.0.RELEASE.jar

spring-context-support-4.3.0.RELEASE.jar

spring-core-4.3.0.RELEASE.jar

spring-expression-4.3.0.RELEASE.jar

spring-web-4.3.0.RELEASE.jar

spring-webmvc-4.3.0.RELEASE.jar

 

2. 配置web.xml,配置spring mvc的分发器(和servlet配置一样)DispatcherServlet,需要在tomcat启动的时候就加载

<load-on-startup>1</load-on-startup>

    <servlet>

<servlet-name>springmvc</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>springmvc</servlet-name>

<url-pattern>*.do</url-pattern>

</servlet-mapping>

 

3. 添加springmvc的配置文件,默认在src下添加dispatcherServletName-servlet.xml,

    注意:dispatcherServletName是web.xml中servlet-name的值,根据这里的配置,应该叫:springmvc-servlet.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:p="http://www.springframework.org/schema/p"

    xmlns:context="http://www.springframework.org/schema/context"

    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">

 

</beans>

  

注:这个配置文件中的内容如何不会写,那么可以到spring的zip中找到dosc/spring-frameworkreference/html

找到The Web模块下的The DispatcherServlet 下的Default DispatcherServlet Configuration配置

 

 

 

4. 编写Controller     

public class HelloControllerimplements Controller{

@Override

public ModelAndView handleRequest(HttpServletRequestarg0, HttpServletResponsearg1)throws Exception {

//ModelAndView是封装要显示到页面的数据

ModelAndView mv =new ModelAndView();

//页面的数据

mv.addObject("msg","你好 spring mvc");

//配置视图的名称

mv.setViewName("hello");

return mv;

}

}

 

5. 配置springmvc配置文件(给第3步的配置文件添加内容)

<?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:p="http://www.springframework.org/schema/p"

    xmlns:context="http://www.springframework.org/schema/context"

    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">

    <!-- 配置HandlerMapping -->

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

<!-- 配置HandlerAdapter -->

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

<!-- 配置页面渲染器,到dosc/html/index.html中搜索Reslover可以找到 -->

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

   <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

   <!-- 配置结果视图的前缀和后缀 -->

   <property name="prefix" value="/WEB-INF/jsp/"/>

   <property name="suffix" value=".jsp"/>

    </bean>

    <!-- 配置请求的处理类 -->

    <bean name="/hello.do" class="com.yirong.controller.HelloController"></bean>

</beans>

 

6. 请求结果

 

 

Spring mvc注解开发

1. 倒入jar

commons-logging-1.1.3.jar

jstl-2.4.jar

servlet-api.jar

spring-aop-4.3.0.RELEASE.jar

spring-beans-4.3.0.RELEASE.jar

spring-context-4.3.0.RELEASE.jar

spring-context-support-4.3.0.RELEASE.jar

spring-core-4.3.0.RELEASE.jar

spring-expression-4.3.0.RELEASE.jar

spring-web-4.3.0.RELEASE.jar

spring-webmvc-4.3.0.RELEASE.jar

 

2. 配置web.xml

<!-- 注解的方式 -->

<servlet>

<servlet-name>springmvc</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>  <!-- 到the web文档中可以查找获得-->

<param-name>contextConfigLocation</param-name>

<param-value>classpath:springmvc.xml</param-value> <!--此配置文件在源码下-->

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>springmvc</servlet-name>

<url-pattern>*.do</url-pattern>

</servlet-mapping>

 

3. 编写controller

package com.yirong.controller.annotation;

 

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

 

@Controller //表示这个是一个Controller 

public class HelloWorldController {

@RequestMapping("/helloWorld") //请求此方法

public String helloWorld(Modelmodel) {

model.addAttribute("msg","Hello World! 你好springmvc注解 ");

return "hello";//视图的名称

}

@RequestMapping("/helloWorld1")//请求此方法

public ModelAndView helloWorldreq(HttpServletRequestarg0, HttpServletResponsearg1)throws Exception {

//ModelAndView是封装要显示到页面的数据

ModelAndView mv =new ModelAndView();

//页面的数据

mv.addObject("msg","你好 spring mvc");

//配置视图的名称

mv.setViewName("hello");

return mv;

}

}

 

 

4. 配置springmvc.xml,这个文件需要和源码放在一起src/*.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:p="http://www.springframework.org/schema/p"

    xmlns:context="http://www.springframework.org/schema/context"

    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">

<!-- 配置页面渲染器 -->

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

   <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

   <!-- 配置结果视图的前缀和后缀,页面路径默认在webContent下-->

   <property name="prefix" value="/WEB-INF/jsp/"/>

   <property name="suffix" value=".jsp"/>

    </bean>

<!--扫描这个文件夹下的类表示是注解的controller。 到the web文档中可以查找获得-->

 <context:component-scan base-package="com.yirong.controller.annotation" />

</beans>

 

5. 效果:

 

 

Controller配置方式

1. 配置开发

2. 注解开发

3. Key对应url请求名的方式

 

<?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:p="http://www.springframework.org/schema/p"

    xmlns:context="http://www.springframework.org/schema/context"

    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">

    <!-- 配置HandlerMapping -->

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

<!-- 配置HandlerAdapter 如果这里不配置,那么请求一定要带上web中配置的结尾,比如.do-->

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

<!-- 配置页面渲染器 -->

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

   <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

   <!-- 配置结果视图的前缀和后缀,页面路径默认在webContent下-->

   <property name="prefix" value="/WEB-INF/jsp/"/>

   <property name="suffix" value=".jsp"/>

</bean>

 

    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

    <property name="mappings">

    <props>

    <prop key="/hello.do">helloController</prop>

    </props>

    </property>

    </bean> 

<bean name="helloController" class="com.yirong.controller.HelloController"></bean>

     

    

</beans>

 

 

4. 控制器类名的方式配置

<?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:p="http://www.springframework.org/schema/p"

    xmlns:context="http://www.springframework.org/schema/context"

    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">

    <!-- 配置HandlerMapping -->

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

<!-- 配置HandlerAdapter 如果这里不配置,那么请求一定要带上web中配置的结尾,比如.do-->

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

<!-- 配置页面渲染器 -->

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

   <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

   <!-- 配置结果视图的前缀和后缀页面默认在webContent下-->

   <property name="prefix" value="/WEB-INF/jsp/"/>

   <property name="suffix" value=".jsp"/>

    </bean> 

    <!-- 控制器类名的方式配置 hello*.do的请求将被匹配-->

    <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>

    <bean name="helloController" class="com.yirong.controller.HelloController"></bean>

</beans>

 

 

Spring mvc结果跳转

1. 设置 ModelAndView对象,视图解释器根据设置的view的名称进行跳转

视图解释器根据springmvc配置文件中的页面的前缀路径+视图名称+springmvc配置文件中的页面的后缀,找到指定页面。

@Override

public ModelAndView handleRequest(HttpServletRequestarg0, HttpServletResponsearg1)throws Exception {

//ModelAndView是封装要显示到页面的数据

ModelAndView mv =new ModelAndView();

//页面的数据

mv.addObject("msg","你好 spring mvc");

//配置视图的名称

mv.setViewName("hello");

return mv;

}

@RequestMapping("/helloWorld")//请求此方法

public String helloWorld(Modelmodel) {

model.addAttribute("msg","Hello World! 你好springmvc注解 ");

return "hello";//视图的名称

}

 

2. 通过servletApi跳转,不使用springmvc的视图解释器

@RequestMapping("/helloWorld1")//请求此方法

public voidhelloWorldreq(HttpServletRequestarg0, HttpServletResponsearg1)throws Exception {

arg1.getWriter().println("你好,springmvc servlet");

        //servlet的重定向和转向设置值等在这里都可以使用

}

 

3. Springmvc实现重定向和转发,没有视图渲染,页面在webcontent,转发,需要带上.jsp没有用到视图渲染器

@RequestMapping("/zhuanfa")

public String zhuanfa(){

 return "forward:zhuanfa.jsp"; //转发 地址栏不变

            //return "redirect:zhuangxiang.jsp"; //转向 地址栏变

}

 

4. Springmvc实现重定向和转发,视图渲染器,转向不需要视图渲染

@RequestMapping("/zhuanfa")

public String zhuanfa(){

return "zhuanfa"; //默认转发

}

 

Spring mvc 是单例的

1. controller添加一个构造方法,在启动时执行一次,而后访问时不会再执行

public HelloWorldController(){

System.out.println("spring mvc 构造方式");

}

 

 

 

Spring mvc接收页面简单数据

1. 创建一个注解方式的spring mvc项目环境,在controller中添加以下方法

/**

 * url参数数据提交,在这里获取数据

 * @param name

 * @return

 */

@RequestMapping("/datas")

public String getData(Stringname){

System.out.println(name);

return "wel";

}

 

2. 访问,注意参数名与上面方法名的形参名相同

http://localhost:8080/springMvcTest/datas.do?name=aacc

 

 

3. 如果url上的参数名与方法是的形参名不同也可以传递参数,改造方法:

/**

 * url参数数据提交,在这里获取数据

 * @param name

 * @return

 */

@RequestMapping("/datas")

public String getData(@RequestParam("un")Stringname){

System.out.println(name);

return "wel";

}

 

4. 访问

http://localhost:8080/springMvcTest/datas.do?un=aaccsdf

 

 

 Spring mvc接收对象数据

要求表单中的name的名称与实体的属性名相同,controller中的方法的形参是实体的对象即可。

spring mvc对基本数据类型会自动转换。

Spring mvc会将传递的值封装到对象中去,并且与形参的名称没有关系。

1. controller中添加一个方法

/**

 * url参数数据提交,在这里获取对象数据

 * @param name

 * @return

 */

@RequestMapping("/dataObj")

public String getDataObj(User user){

System.out.println(user.toString());

return "wel";

}

 

2. 添加User对象,属性需要有get set方法

package com.yirong.controller.annotation;

 

public class User {

private Stringname;

private Integerage;

private Stringtel;

 

public String getName() {

return name;

}

public void setName(Stringname) {

this.name =name;

}

public Integer getAge() {

return age;

}

public void setAge(Integerage) {

this.age =age;

}

public String getTel() {

return tel;

}

public void setTel(Stringtel) {

this.tel =tel;

}

@Override

public String toString() {

return "User [name=" +name +", age=" + age +", tel=" +tel + "]";

}

}

 

 

3. 效果

http://localhost:8080/springMvcTest/dataObj.do?name=myname&age=1

 

 

Spring mvc将数据显示到UI

ModelAndView的方式

public class HelloControllerimplements Controller{

@Override

public ModelAndView handleRequest(HttpServletRequestarg0, HttpServletResponsearg1)throws Exception {

//ModelAndView是封装要显示到页面的数据 

//这相当于是request.setAttribute的方式

ModelAndView mv =new ModelAndView();  

//页面的数据

mv.addObject("msg","你好 spring mvc");

//配置视图的名称

mv.setViewName("hello");

return mv;

}

}

 

 

1. 页面用el表达式即可

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>springmvc转发</title>

</head>

<body>

springmvc转发sdf

<br> 

${msg}

</body>

</html

 

ModelMap的方式

1. 注:modelmap一定要放在controller的方法中做为形参

/**

 * url参数数据提交,在这里获取对象数据

 * @param name

 * @return

 */

@RequestMapping("/dataObj")

public String getDataObj(Useruser,ModelMap modelMap){

System.out.println(user.toString());

//将数据显示到页面

modelMap.addAttribute("myvalue","值,va");

return "wel";

}

 

2. 页面

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>springmvc转发</title>

</head>

<body>

springmvc转发sdf

<br> 

${myvalue }

</body>

</html>

 

3. 效果

 

 

 

ModelAndView与ModelMap方式比较

相同点:都可以将数据封装显示到视图

不同点:ModelAndView可以指定跳转的视图,而ModelMap不能

ModelAndView需要视图解析器,ModelMap可以不需要

Spring mvc解决乱码

Get方式乱码

配置tomcat即可

找到conf/server.xml中端口设置的地方,添加 URIEncoding="UTF-8"

添加完成之后:

 <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"  URIEncoding="UTF-8" />

 

1. 传递中文到controller

/**

 * url参数数据提交,在这里获取数据

 * @param name

 * @return

 */

@RequestMapping("/datas")

public String getData(@RequestParam("un")Stringname,ModelMap map){

System.out.println(name);

        map.addAttribute(“myvalue”,name);

return "wel";

}

 http://localhost:8080/springMvcTest/datas.do?un=你好springmvc

2. 效果,中文在controller中拿到是乱码

解决之前:乱码

         

解决之后:

         

再传递到页面(注:页面的编码要是utf-8,浏览器的编码也需要是utf-8):

 

 

Post方式乱码

Spring mvc 中解决乱码是通过CharacterEncodingFilter过滤器来解决的,因此需要在web.xml中配置。并且CharacterEncodingFilter主要是用于解决post请求的乱码,

get请求方式的乱码需要用到tomcat或jsp页面设置的方式进行解决

注:此配置需要配置在DispatcherServlet之前

<filter>

<filter-name>CharacterEncodingFilter</filter-name>

<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

<init-param>

<param-name>encoding</param-name>

<param-value>utf-8</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>CharacterEncodingFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

1. 页面:

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>乱码解决</title>

</head>

<body>

 <form action="/springMvcTest/datas.do" method="post">

 <input type="text" name="un" />

 <input type="submit" value="提交" />

 </form>

</body>

</html>

2. 效果:

 

 

 

 

Spring mvc url请求风格1

package com.yirong.controller.annotation;

 

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

 

@Controller //表示这个是一个Controller

@RequestMapping("/hello2")

public class Hello2Controller {

@RequestMapping(params="method=add",method=RequestMethod.POST) //请求此方法一定要是post方式

public String helloWorld(Model model) {

model.addAttribute("msg", "Hello World! 你好springmvc注解  params");

return "WEB-INF/jsp/hello"; //视图的名称

}

}

 

package com.yirong.controller.annotation;

 

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

 

@Controller //表示这个是一个Controller

@RequestMapping("/hello2")

public class Hello2Controller {

@RequestMapping(params="method=add",method=RequestMethod.GET)  //请求此方法一定要是GET方式

public String helloWorld(Model model) {

model.addAttribute("msg", "Hello World! 你好springmvc注解  params");

return "WEB-INF/jsp/hello"; //视图的名称

}

}

 

 

Restful风格@PathVariable

Restful风格:轻量级,安全,效率高

Controller中的方法:

@RequestMapping("/{uid}/del/{id}")

public String del(@PathVariable Integerid,@PathVariable("uid") Integer uid,ModelMapmodelMap){

System.out.println(id);

System.out.println(uid);

//将数据显示到页面

modelMap.addAttribute("myvalue",id);

return "wel";

}

@PathVariable表示这个参数是路径带过来的参数

Restful风格的写法还可以这样:

@RequestMapping("/del/{id}/{uid}")

@RequestMapping("/{id}/del//{uid}")

 

效果:

http://localhost:8080/springMvcTest/111/del/222.do

 

 

详解@RequestMapping

@RequestMapping可以修饰在类上面,表示指定的目录为这个类请求的url,也可以修饰在方法上面表示请求的是某个方法

标识url的方式:@RequestMapping(“url”)

表识参数和方法还有头的请求方式:

@RequestMapping(value="/rmtest",params={"name","age!=10"},method=RequestMethod.GET,headers={"Accept-Language=zh-CN,zh;q=0.8"})

Value表示:url

Params表示:请求的url必须带上指定参数,而且age的值!=10,否则404

Method表示:请求的方式一定指定方式,这里是GET,否则404

Headers表示:http请求的头的内容,其中这里指定Accept-Language的值一定要是zh-CN,zh;q=0.8,否则404

 

:

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

 

@Controller //表示这个是一个Controller

public class RmTest {

@RequestMapping(value="/rmtest",params={"name","age!=10"},method=RequestMethod.GET,headers={"Accept-Language=zh-CN,zh;q=0.8"})//请求此方法

public String helloWorld(Modelmodel) {

model.addAttribute("msg","Hello World! 你好springmvc注解  rmtest");

return "WEB-INF/jsp/hello";//视图的名称

}

}

 

效果:

 

 

 

详解@RequestMapping ant风格url

此方式了解即可

Ant风格资源地址支持3种匹配符:

 ? : 匹配文件名中的一个字符

 * : 匹配文件名中的任意字符

** :  匹配多层路径

@RequestMapping对ant风格url的支持,例:

 

 

:

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

 

@Controller //表示这个是一个Controller

public class RmTest {

@RequestMapping("/antUrl/*/t")//请求此方法

public String testAntUrl(Modelmodel) {

model.addAttribute("msg","Hello World! 你好springmvc注解  anturl");

return "WEB-INF/jsp/hello";//视图的名称

}

}

 

 

详解@PathVariable

 

详解Restful

 

 

http://kb.cnblogs.com/page/186516/

http://www.infoq.com/cn/articles/rest-introduction

 

比如:

 

案例

 

package com.yirong.controller.annotation;

 

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

 

@Controller // 表示这个是一个Controller

public class RestfulTest {

 

@RequestMapping(value="/testRestfulUrl",method=RequestMethod.POST)

public String add(Ordero, Modelmodel) {

System.out.println(o.toString());

model.addAttribute("msg","Hello World! 你好springmvc注解  restful 添加 post 请求");

return "order/add";

}

 

@RequestMapping(value="/testRestfulUrl/{id}",method=RequestMethod.GET)

public String get(@PathVariable("id") Integer id, Modelmodel) {

System.out.println(id);

model.addAttribute("msg","Hello World! 你好springmvc注解  restful 通过id查一个对象的信息 get请求");

return "order/add";

}

@RequestMapping(value="/testRestfulUrl/{id}",method=RequestMethod.DELETE)

public String delete(@PathVariable("id") Integer id, Modelmodel) {

System.out.println(id);

model.addAttribute("msg","Hello World! 你好springmvc注解  restful 删除 delete请求");

return "order/add";

}

 

@RequestMapping(value="/testRestfulUrl/{id}",method=RequestMethod.PUT)

public String put(@PathVariable("id") Integer id, Modelmodel) {

System.out.println(id);

model.addAttribute("msg","Hello World! 你好springmvc注解  restful 修改 put请求");

return "order/add";

}

}

 

 

页面:webContent/order/下

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>restful</title>

</head>

<body>

添加:<br />

 <form action="/springMvcTest/testRestfulUrl.do" method="post">

 <input type="text" name="orderName" />

 <input type="text" name="number" />

 <input type="submit" value="提交" />

 </form>

 获得:<br />

 <a href="/springMvcTest/testRestfulUrl.do/1">获取id=1的数据</a>

 

 删除:<br />

  <form action="/springMvcTest/testRestfulUrl.do/1" method="post">

 <input type="hidden" name="_method" value="DELETE"/>

 <input type="submit" value="提交" />

 </form>

 

 修改<br />

  <form action="/springMvcTest/testRestfulUrl.do/1" method="post">

 <input type="hidden" name="_method" value="PUT"/>

 <input type="submit" value="提交" />

 </form>

  <br />

 <br />

 <br />

 ${msg}

</body>

</html>

Web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">

 

<!-- HiddenHttpMethodFilter是spring3.0之后新增的一个过滤器,可以将post请求转为put和delete请求,

对实现rest风格有了更好的支持 -->

<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>

<filter>

<filter-name>CharacterEncodingFilter</filter-name>

<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

<init-param>

<param-name>encoding</param-name>

<param-value>utf-8</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>CharacterEncodingFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

 

<!-- 配置的方式

<servlet>

<servlet-name>springmvc</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>springmvc</servlet-name>

<url-pattern>*.do</url-pattern>

</servlet-mapping>     -->

 

<!-- 注解的方式-->

<servlet>

<servlet-name>springmvc</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<init-param>  

<param-name>contextConfigLocation</param-name>

<param-value>classpath:springmvc.xml</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>springmvc</servlet-name>

<url-pattern>/</url-pattern>

</servlet-mapping> 

</web-app>

 

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" 

       xsi:schemaLocation="http://www.springframework.org/schema/beans

       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/mvc

http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd

        http://www.springframework.org/schema/context

        http://www.springframework.org/schema/context/spring-context.xsd"

       default-lazy-init="true">     

 

<!-- 配置页面渲染器 -->

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

   <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

   <!-- 配置结果视图的前缀和后缀 -->

   <property name="prefix" value="/"/>

   <property name="suffix" value=".jsp"/>

    </bean>

   <mvc:annotation-driven /> <!-- 基于Schema-based XML的配置定义模式 -->

    <context:component-scan base-package="com.yirong.controller.annotation" />

</beans>

 

 

详解@RequestParam

在上面例子的类中添加以下方法:

@RequestMapping(value="/testRequestParam")

public String testRequestParam(@RequestParam(value="userName") String userName,

@RequestParam(value="age",required=true,)Integer age

           //@RequestParam(value="age",required=false,defaultValue="0")int age, Modelmodel) {

model.addAttribute("msg","Hello World! 你好springmvc注解   requestParam "+userName+" age="+age);

return "order/list";

}

 

List.jsp:在webContent/order/下

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>requestParam</title>

</head>

<body>

 <form action="/springMvcTest/testRequestParam" method="post">

 <input type="text" name="userName" />

 <input type="text" name="age" />

 <input type="submit" value="提交" />

 </form>

 ${msg }

</body>

</html>

 

:@RequestParam(value="age",required=true)value表示为参数名称,在form表单中需要一一对应.

Required=true表示此参数是必须的,如果不写或把值改为false表示该参数不是必须的,但是要注意:如果是一个Integer类型的值,也就是数字,那么在这里接收参数的类型一定要是Integer对象,不能是int类型,否则当此参数被用到时而又并未给相应的值(当此参数不是必须时),那么就会出现异常

 

如果一定需要传递int类型,那么需要添加一个配置:@RequestParam(value="age",required=false,defaultValue="0")int age

表示默认值为0,如果没有传递age,那么默认为0.

 

了解@RequestHeader

此注解与详解@RequestMapping的headers参数是一个意思,用法与@RequestMapping相同,表示指定请求头包含指定参数名.了解即可.

 

 

详解@CookieValue

此注解可以让处理方法的入参绑定某个Cookies的值,表示是从cookies中取指定参数名称的值.

每一次请求都有一个JSESSIONID,那么我们可以通过@CookiesValue这个注解将JSESSIONID通过处理方法入参的方式获得

 

@RequestMapping(value="/testCookiesValue")

public String testCookiesValue(@CookieValue(value="JSESSIONID") String sessionId,

@RequestParam(value="age") Integerage, Modelmodel) {

model.addAttribute("msg","Hello World! 你好springmvc注解   @CookieValue "+sessionId+" age="+age);

return "order/list";

}

 

Cookies.jsp:在webcontent/order/下

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>requestParam</title>

</head>

<body>

 <form action="/springMvcTest/testCookiesValue" method="post"> 

 <input type="text" name="age" />

 <input type="submit" value="提交" />

 </form>

 ${msg }

</body>

</html>

效果:正常的取到cookies中的值

 

 

详解将Pojo做为参数传递

在前面已实现将对象做为参数传递到spring mvc的controller中,在传递的过程中,spring mvc

会将指定的参数名自匹配到pojo的属性名中,并且还会填充值到pojo的属性中.且支持级联属性.

 

案例1:

:controller中@RequestMapping的写法,在类上有注解,在方法上也有注解,并且处理的方法中的参数为Model model 这是对应的,不能错写.

:Model model可以去掉不要,即类和方法同时有@RequestMapping注解那么处理方法可添加Model model可不添加,但不能添加ModelMap做为视图数据封装类

 

OrderController:

package com.yirong.controller.annotation;

 

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping("order")

@Controller //表示这个是一个Controller

public class OrderController {

@RequestMapping("/add")//请求此方法

public String add(Orderorder,Model model) {

System.out.println(order.toString());

model.addAttribute("msg","添加订单成功 "+order.toString());

return "wel";//视图的名称wel.jsp页面只是一个成功页面,内容为”成功页面”

} 

}

Order.java

package com.yirong.controller.annotation;

 

public class Order {

private StringorderName;

private Integernumber;

private Useruser;

 

public String getOrderName() {

return orderName;

}

 

public void setOrderName(StringorderName) {

this.orderName =orderName;

}

 

public Integer getNumber() {

return number;

}

 

public void setNumber(Integernumber) {

this.number =number;

}

 

public User getUser() {

return user;

}

 

public void setUser(Useruser) {

this.user =user;

}

 

@Override

public String toString() {

return "Order [orderName=" +orderName +", number=" +number + ", user=" +user +"]";

}

 

}

 

 

User.java

package com.yirong.controller.annotation;

 

public class User {

private Stringname;

private Integerage;

private Stringtel;

 

public String getName() {

return name;

}

public void setName(Stringname) {

this.name =name;

}

public Integer getAge() {

return age;

}

public void setAge(Integerage) {

this.age =age;

}

public String getTel() {

return tel;

}

public void setTel(Stringtel) {

this.tel =tel;

}

@Override

public String toString() {

return "User [name=" +name +", age=" + age +", tel=" +tel + "]";

}

}

 

 

addOrder.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>restful</title>

</head>

<body>

添加订单:<br />

 <form action="/springMvcTest/order/add" method="post">

 订单名称:<input type="text" name="orderName" /><br />

 数量:<input type="text" name="number" /><br />

 用户名:<input type="text" name="user.name" /><br />

 年龄:<input type="text" name="user.age" /><br />

 电话:<input type="text" name="user.tel" /><br />

 <input type="submit" value="提交" /><br />

 </form>

 <br />

</body>

</html>

 

案例2:

:controller中@RequestMapping的写法,只在方法上也有注解,并且处理的方法中的参数为ModelMap modelMap这是对应的,不能错写.

:ModelMap modelMap可以去掉不要,即只方法有@RequestMapping注解那么处理方法可添加ModelMap modelMap可不添加,但不能添加Model做为视图数据封装类

Order2Controller:

package com.yirong.controller.annotation;

 

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.ui.ModelMap;

import org.springframework.web.bind.annotation.RequestMapping;

 

@Controller //表示这个是一个Controller

public class Order2Controller {

 

@RequestMapping("/order2")//请求此方法

public String order2(Orderorder,ModelMap modelMap) {

System.out.println(order.toString());

modelMap.addAttribute("msg","添加订单成功  "+order.toString());

return "wel";//视图的名称wel.jsp页面只是一个成功页面,内容为”成功页面”

}  

}

 

 

Order.java和User.java参考案例1

 

addOrder.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>restful</title>

</head>

<body>

添加订单2:<br />

 <form action="/springMvcTest/order2" method="post">

 订单名称:<input type="text" name="orderName" /><br />

 数量:<input type="text" name="number" /><br />

 用户名:<input type="text" name="user.name" /><br />

 年龄:<input type="text" name="user.age" /><br />

 电话:<input type="text" name="user.tel" /><br />

 <input type="submit" value="提交" /><br />

 </form>

</body>

</html>

 

详解spring mvc接收servlet原生api参数

Spring mvc的Handler方法可以接受Servlet api的以下类型做为参数:

HttpServletRequest

HttpServletResponse

HttpSession

java.security.Principal

Locale

InputStream

OutputStream

Reader

Writer

 

 

:

添加一个方法到controller中

@RequestMapping("/servApi")

public void servApi(HttpServletRequestrequest,HttpServletResponseresponse,Writerout)throws IOException {

request.setCharacterEncoding("UTF-8");

System.out.println(request+" , "+response);

out.write("spring mvc servlet  api");

//return "wel"; //视图的名称

}

 

页面请求:

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>servlet  </title>

</head>

<body> 

 <a href="/springMvcTest/servApi">servlet 原生api</a>

</body>

</html>

 

效果:

 

 

详解spring mvc 处理模型数据

Spring mvc 会将模型数据对象中的数据添加到request对象中

原码:InternalResourceView.renderMergedOutputModel() -> AbstractView.exposeModelAsRequestAttributes()

ModelAndView

ModelAndView是一个视图数据封装器,其包含了视图信息和模型数据信息,在controller处理类返回该对象时,直接new操作即可

:

/**

 * ModelAndView 的使用

 * 可以通过new ModelAndView时将视图名称添加到ModelAndView中

 * 也可以通过modelAndView.setViewName("wel");设置

 * @return

 */

@RequestMapping("testModAndView")

public ModelAndView testModelAndView(){

ModelAndView modelAndView =new ModelAndView("wel");

modelAndView.addObject("time",new Date());

return modelAndView;

}

 

Map和Model

Map and Model 需要写在controller类的处理类的形参中,以参数的方式处理模型数据,其类型为org.springframework.ui.Model和

org.springframework.ui.ModelMap或java.util.Map,spring mvc框架在渲染视图时会自动将需要渲染的数据添加到模型中.

Spring mvc 在调用方法前会创建一个隐含的模型对像作为模型数据的存储容器.如果方法的入参为Map或Model类型时,spring mvc会将隐含模型的引用传递给入参.开发者可以通过入参对象访问到模型中所有的数据,也可以向模型中添加新的数据,以渲染到视图.

Spring mvc model类关系:

 

 

 

Controller类中的方法:

/**

 * spring mvc 的controller类的处理方法的形参可以是一个map,而这个map其实是

 * spring mvc提供的org.springframework.validation.support.BindingAwareModelMap的实例

 * @return

 */

@RequestMapping("/testMap")

public String testMap(Map<String,Object>map){

map.put("msg",Arrays.asList("aa","bb","cc",map.getClass().getName()));

return "wel";

}

 

Wel.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>springmvc </title>

</head>

<body>

<br>  

${msg } 

</body>

</html>

 

Model 与 ModelMap入参的方式处理模型数据在前面章节中已有详细例子.

 

详解@SessionAttributes

如需在多个请求之间共享某个模型属性数据,则可以在controller类上添加此注解,@SessionAttribute注解只能添加在类上面

Spring mvc 会将在模型中对应的属性暂存到HttpSession中.

@SessionAttributes可以通过指定属性名将相应的值放入session以外,还可以通过模型属性中的对象类型将值放入到session中

:

@SessionAttributes(types=User.class) 会将隐含模型中所有类型为User.class的属性和值添加到session中

@SessionAttributes(value={“username”,”age”}) 会将隐含模型中属性名为username和age的属性和值添加到session中

@SessionAttributes(types={User.class},value={“username”,”age”})同上意

1. @SessionAttributes 的Value属性表示是将指定的属性放进session

2. @SessionAttributes 的Type属性表示是将指定的类型的属性全放进session

3. @SessionAttributes注解只能添加在类上面

 

 

package com.yirong.controller.annotation;

 

import java.util.Arrays;

import java.util.Date;

import java.util.Map;

 

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.SessionAttributes;

import org.springframework.web.servlet.ModelAndView;

 

@SessionAttributes(value={"user"},types={String.class})

@Controller

public class ModelViewController {

@RequestMapping("/testSessionAttri")

public String testSessionAttri(Map<String,Object>map){

User user =new User();

user.setAge(10);

user.setName("张三");

user.setTel("13445678945");

map.put("user",user);

map.put("addr","shenzhen");

return "wel";

}

}

 

页面:

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>springmvc </title>

</head>

<body>

 <br >

request user: ${requestScope.user } <br >

session user: ${sessionScope.user } <br >  

request addr: ${requestScope.addr }<br >

session addr: ${sessionScope.addr }<br >

</body>

</html>

 

详解@ModelAttribute

应用场景

通过一个修改操作来了解ModelAttribute使用场景

 

解决问题:

在更新之前应该从数据中根据ID拿出需要修改的数据对象A ,然后将要修改的数据填充到A对象中,那么不需要修改的数据在A对象中本身就存在而且是从数据库中填充的,这样更修后就不存在上所描述的问题.这就是ModelAttribute使用的场景(Struts2中有一个类似功能的拦截器)

代码:

package com.yirong.controller.annotation;

 

import java.util.Arrays;

import java.util.Date;

import java.util.Map;

 

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.ModelAttribute;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam; 

import org.springframework.web.servlet.ModelAndView;

 

//@SessionAttributes(value={"user"},types={String.class}) 注意这个要删除,否则有500 后面章节讲解

@Controller

public class ModelViewController {

 

@RequestMapping("/testModelAttribute")

//public String testModelAttribute(@ModelAttribute(“user”)Useruser) {

public String testModelAttribute(Useruser) {

System.out.println(user.toString());

return "wel";

}

/**

 * 有@ModelAttribute标记的方法,会在每个目标方法执行之前被spring mvc框架调用

 * @param id

 * @param map

 */

@ModelAttribute

 //不加此注解,在页面输入新数据点修改后,testModelAttribute方法打应的对象中tel的值为null

public void getUser(@RequestParam(value="id",required=false) Integer id

,Map<String,Object> map){

if (null != id) {

User user = new User();

user.setName("zhangsan");

user.setAge(12);

user.setTel("13400000000");

System.out.println("模拟从数据库中取数据完成  "+user.toString());

map.put("user", user);

}

}

}

 

test.jsp页面:

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>springmvc </title>

</head>

<body>

<br />

 模拟修改操作:<br />

原始数据:id : 1 name :zhangsan age: 12tel:13400000000<br />

修改后的值为: id : 1  name:lisi age:20 tel不修改<br />

<br />

<form action="/springMvcTest/testModelAttribute">

<input type="hidden" name="id" value="1" />

名称:<input type="text" name="name" value="zhangsan"/><br />

年龄<input type="text" name="age" value="12"/><br />

<input type="submit"  value="修改" />

</form>

</body>

</html>

 

效果:

 

 

 

原理

根据上面例子,简单运行流程:

1. 并在执行testModelAttribute方法之前,执行@ModelAttribute注解的方法getUser,把获取的对象放进Map中,key为user

2. Spring mvcww map中取出user对象,并把表单中的数据封装到对象中的相应属性

3. 再执行testModelAttribute方法(也就是目标方法)

:@ModelAttribute注解的方法中将对象放入到map时,key需要和目标方法的入参的类型首字母小写后的字符串相同

上例: testModelAttribute方法的入参类型是User,那么首字母小写后为user,则在@ModelAttribute注解的方法中的map设置值时的key也需要为user

 

 走原码:在以下几个关键点打断点,然后观察map中对象的值的变化,可以看到封装流程

HandlerMethodInvoker

1. ->invokeHandlerMethod():

 

: 

ExtendedModelMap implicitModel) throws Exception {

 

2.  ->resolveModelAttribute():

 

3. ->resolveHandlerArguments():

 

:

 

再到:AbstractBindingResult->getModel()

 

原码原理:

1. 调用@ModelAttribute注解的方法后,把@ModelAttribute方法中的Map中的数据放在了implicitModel中.

2. 解析请求处理器的目标参数,数据来自WebDataBinder对象的target属性

a) 创建WebDataBinder对象,

b) 获得objectName属性:若attrName属性值为””,则objectName为类名第一个字母小写

i. 若目标方法的入参的Pojo使用了@ModelAttribute来修饰,那么attrName的值就为@ModelAttribute(value指定的值)

c) 获得target属性

i. implicitModel中查找attrName对应的属性值,若存在直接取

ii. 不存在,则验证当前Controller是否使用了@SessionAttributes注解,如用了则从session中取attrName所对应属性的值,如取不到则抛异常

iii. 如果没有用@SessionAttributes注解或@SessionAttributes中使用value的值指定的key和attrName不相匹配,那么通过反射创建pojo对象进行处理

 

  

3. Spring mvc 把表单的请求参数赋给了webDataBinder的target对应的属性,再将attrName和target赋给implicitModel,最后将对象(target)传给目标方法入参

 

 

Spring mvc 确定目标方法pojo类型入参的过程

1. Spring mvc框架在获取目标方法的参数时,首先判断入参的POJO是否有用@ModelAttribute注解,如果没有,则直接使用POJO的首字母小写后的字符串做为KEY

如果有使用则直接用@ModelAttribute注解的value的值做为KEY

2. 使用时在implicitModel中查找key对应的对象,存在就则为入参传入,如找不到key则则检查当前的Handler是否使用了@SessionAttributes注解,如果用了,且能在session中找到相应的key,则从session中取key,否则抛异常.如果没有用或用了但没有包含相应的KEY,则会通过反射POJO来处理

3. Spring mvc把key和pojo类型的对象保存到imlicitModel中,再保存到request中

 

 

最终得出@ModelAttribute注解的特点:

1. @ModelAttribute注解的方法会在每个目标方法执行之前被spring mvc调用

2. @ModelAttribute注解也可以用来修饰目标方法的POJO类型的入参,其value属性值有以下作用:

a) Spring mvc 会相济 value属性值在implicitModel中查找对应的对象,若存在则会直接传入到目标方法的入参中.

b) Spring mvc 会以 注解的value的值做为 key ,POJO做为value的方式存入到request中

 

@SessionAttributes与@ModelAttribute同用时的异常

根据以上原理分析,注解了@ModelAttribute时,当controller中没明确了标识了所需的key时,而又同时使用了@SessionAttributes注解,那么就会到session中去找@ModelAttribute所标识的key的值或因为默认的值与@SessionAttributes注解的key相同时,那么就可能会发生异常.

解决办法,@ModelAttribute注解value的值与@SessionAttributes注解的value的值不要相同,或如果没必要则不要随便注解@SessionAttributes

 

doDispatch

 

processDispatchResult

 

 

 

Render

 

 

 

 

 

 

注解详说:

http://www.cnblogs.com/xiepeixing/p/4243288.html

 

 

InternalResourceViewResolver

 

1. 若项目中使用了jstl,则spring mvc会自动把视图由InternalResourceView转为JstlView

2. 如果使用了jstl的fmt标签则需要在spring mvc的配置文件中配置国际化资源文件

<bean id="messageSource"  class="org.springframework.context.support.ResourceBundleMessageSource">

    <property name="basename" value="i18n"></property>

</bean>

3. 如果希望直接响应通过spring mvc渲染的页面,可以使用<mvc:view-controller>标签来实现

<mvc:view-controller

path="/springMvcTest/testJstlView" view-name="wel" />

 

 

<mvc:view-controller>

用于配置直接转发的页面,不需要经过controller,直接输入配置的/aa就会请求到wel视图

<mvc:view-controller

path="/aa"view-name="wel" /> 

 

这样的请求方式适用于,有些页面不需要任何controller处理逻辑就要响应的页面

:如果需要用<mvc:view-controller>,那么一定要加上<mvc:annotation-driven />,否则除<mvc:view-controller>配置有效外,其他的url都为404

 

Spring mvc处理静态资源

优雅的rest风格的资源url不希望带.html或.do等后缀,所以在web.xml中配置DispatcherServlet过滤请求时配置的是/,则spring mvc在捕获web容器的所有请求,包括静态资源的请求,如:js时也会将它们当成一个普通的请求处理,因此将不能在controller中找到请求而报404

解决问题:

spring mvc的配置文件中添加一个<mvc:default-servlet-handler />

原理:

<mvc:default-servlet-handler />将在spring mvc 上下文中定义一个DefaultServletHttpRequestHandler它会对进入DispatcherServlet的请求进行筛查,如果是没有经过映射的请就将该请求交给web应用服务器默认的servlet处理,如果不是静态资源就由DispatcherServlet处理.

:一般web应用服务器默认的servlet的名称都是default,如使用的web服务器的默认servlet名称不是default,则需要通过default-servlet-name属性显示的指定:

<mvc:default-servlet-handler default-servlet-name="servlet名称" />

 

 

Spring mvc 的标签库

Spring mvc没有提供循环的标签,所以如果需要的话还需要使用原生的jstl的c标签

但是spring mvc提供了form标签:

<%@ taglib uri="http://www.springframework.org/tags/form"prefix="form"%>

Form标签可以快速的编写表单页面,并能方便的进行表单数据回显,

:(spring mvc默认是认为表单是一定需要回显的)可以通过form表示的modelAttribute属性来绑定属性模型,

如果没有绑定,spring mvc默认从request域对象中读取command的表单bean,如果该属性值不存在,则发生异常.

所以modelAttribute属性在表单上不能少,并且需要绑定一个bean,而在表单中的标签的name就是这个bean的属性名称

Java代码:

@RequestMapping("/add")

public String testSessionAttri(Map<String, Object>map) {

map.put("user",user);

return "wel";

}

 

<form:form action="add" method="post" modelAttribute="数据回显的对象名user">

<form:input path="实体属性名"/>

<form:radiobuttons path="sex"  items="${sexMap }"/>

<form:checkbox path="" />

<form:select path=""  items="下拉的对象" 

itemLabel="下拉的对象名称属性,用于显示" itemValue="选中后获取的值"></form:select>

</form:form>

作业:

spring mvc ,mysql jsp,jstl,实现一个模块的CRUD,用 restful风格

:spring mvc在删除的时候需要用post请求方式,因为url默认是get请求,所以需要模拟一个post提交方式,需要借助jquery:

<script type="text/javascript" src="jquery.2.1.js"></script> 

<script>

$(function (){

$("#delBtn").click(function (){

var href =  $(this).attr("href");

$("#delFormId").attr("action",href).submit();

return false;

});

});

</script>

<form id="delFormId" action="" method="Post">

<input type="hidden" name="_method" value="DELETE">

</form>

<a href="/del/${id}" id="delBtn">删除</a>

 

mvc:annotation-driven

<mvc:annotation-driven />会自动注册RequestMappingHandlerMapping,RequestMappingHandlerAdapterExceptionHandlerExceptionResolver三个bean

还提供以下支持:

支持使用ConversionService实例对表单参数进行类型转换

支持使用@NumberFormatannotation.@DateTimeFormat注解完成数据类型的格式化

支持使用@Valid注解对javabean实例进行jsr 303验证

支持使用@RequestBody和@ResponseBody注解

@InitBinder

@InitBinder注释的方法可以对WebDataBinder对象进行初始化,WebDataBinder是DataBinder的子类,用于完成表单字段到javaBean属性的绑定

@InitBinder注释的方法不能有返回值,必须是void的

@InitBinder注释的方法的参数通常是WebDataBinder

@InitBinder

public void initBinder(WebDataBinderdataBinder){

dataBinder.setAllowedFields("name");

}

使用场景:当添加订单时,表单有一个字段是选择商品,商品是可以选多个的那么这时往往是选中了商品的ID传往后台,而如果是集合或是对像,那么这个时候框架是无法完成在页面选择的是一个ID,

而在后台需要装一个集合或对象的转换的,那么就需要手动转换,那么就用到了@InitBinder注释,表示告诉框架忽略指定字段的转载.

数据格式化和格式化异常消息提示

配置文件复制”spring mvc 注解开发第4点的配置文件”

在前面的例子中的user 类中添加以下 属性:

@DateTimeFormat用于标注在实体类的日期字段上,指定日期的格式,如不标记数据无法获取

@DateTimeFormat(pattern="yyyy-MM-dd")

private Datebirth;

 

public Date getBirth() {

return birth;

}

public void setBirth(Datebirth) {

this.birth =birth;

}

在前面的例子中的 order类中添加以下 属性:

 

@NumberFormat用于标注在实体类的浮点字段上,指定浮点的格式,如不标记数据无法获取

@NumberFormat(pattern="#,###,###.#")

private Floatprice;

public Float getPrice() {

return price;

}

public void setPrice(Float price) {

this.price =price;

}

 

页面:

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>restful</title>

</head>

<body>

 添加订单:<br />

 <form action="/springMvcTest/order/add" method="post">

 订单名称:<input type="text" name="orderName" /><br />

 数量:<input type="text" name="number" /><br />

     价格:<input type="text" name="price"/><br />

 用户名:<input type="text" name="user.name" /><br />

 年龄:<input type="text" name="user.age" /><br />

 电话:<input type="text" name="user.tel" /><br />

 生日:<input type="text" name="user.birth" /><br />

 <input type="submit" value="提交" /><br />

 </form>

 <br />

</body>

</html>

Controller

@RequestMapping("/add")//请求此方法

public String add(Orderorder,BindingResult bindResult,Modelmodel) {

if (bindResult.getErrorCount() > 0){

System.out.println("转换出错");

for (FieldErrorerror:bindResult.getFieldErrors()){

System.out.println(error.getField()+" : "+error.getDefaultMessage());

}

}

System.out.println(order.toString());

model.addAttribute("msg","添加订单成功 "+order.toString());

return "wel";//视图的名称

}

 

结果:

转换出错

price : Failed to convert property value of type [java.lang.String] to required type [java.lang.Float] for property 'price'; nested exception isjava.lang.NumberFormatException: For input string: "a"

user.birth : Failed to convert property value of type [java.lang.String] to required type [java.util.Date] for property 'user.birth'; nested exception isorg.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.format.annotation.DateTimeFormat java.util.Date] for value 's'; nested exception isjava.lang.IllegalArgumentException: Parse attempt failed for value [s]

Order [orderName=1, number=1, user=User [id=null, name=1, age=13, tel=1, birth=null]]

 

Order order,BindingResult bindResult

BindingResult 是框架提供的封装错误信息的处理类,做为参数放在controller类中的处理方法上,并且一定要与实体类参数挨着,

原理:

 

 

 

 

 

自定义类型转换器

添加类型转换器:

package com.yirong.controller.annotation;

 

import org.springframework.core.convert.converter.Converter;

import org.springframework.stereotype.Component;

 

@Component

public class OrderConverterimplements Converter<String,Order>{

 @Override

public Order convert(Stringsource) {

//逻辑内容,将页面获取的内容封装到order对象中,再把对象返回回去,那么在controller得到的对象就有值

Order order =new Order();

if (null !=source) {

System.out.println(source);

order.setOrderName(source);

}

return order;

}

}

 

 

Controller

package com.yirong.controller.annotation;

 

import java.io.IOException;

import java.io.Writer;

 

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.validation.BindingResult;

import org.springframework.validation.FieldError;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;

@RequestMapping("order")

@Controller //表示这个是一个Controller

public class OrderController {

@RequestMapping("/addConverter")//请求此方法

public String add1(@RequestParam("order") Orderorder,Modelmodel ) { 

System.out.println(order.toString()); 

model.addAttribute("msg","添加订单成功 "+order.toString());

return "wel";//视图的名称

}

}

 

页面:

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>restful</title>

</head>

<body>

添加订单1:<br />

 <form action="/springMvcTest/order/addConverter" method="post">

 订单名称:<input type="text" name="order" /><br />

 <input type="submit" value="提交" /><br />

 </form>

</body>

</html>

 

配置文件:

<?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-3.0.xsd

http://www.springframework.org/schema/mvc

http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd

        http://www.springframework.org/schema/context

        http://www.springframework.org/schema/context/spring-context.xsd"

       default-lazy-init="true"> 

<!-- 配置页面渲染器 -->

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

   <property name="viewClass"value="org.springframework.web.servlet.view.JstlView"/>

   <!-- 配置结果视图的前缀和后缀 -->

   <property name="prefix" value="/"/>

   <property name="suffix"value=".jsp"/>

    </bean>    

 <mvc:annotation-driven conversion-service="orderConverterId" />

     <mvc:default-servlet-handler/>

 <bean id="orderConverterId"  class="org.springframework.context.support.ConversionServiceFactoryBean">

    <property name="converters">

    <set>

    <ref bean="orderConverter"/> <!--以应转换器的类名,首字母小写-->

    </set>

    </property>

</bean>

</beans>

 

JSR 303(数据效验)

 

 

 

 

 

 

添加jsr 303支持jar包

hibernate-validator-5.4.0.Final.jar

hibernate-validator-annotation-processor-5.4.0.Final.jar

classmate-1.3.1.jar

jboss-logging-3.3.0.Final.jar

validation-api-1.1.0.Final.jar

 

添加配置文件

<?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-3.0.xsd

http://www.springframework.org/schema/mvc

http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd

        http://www.springframework.org/schema/context

        http://www.springframework.org/schema/context/spring-context.xsd"

       default-lazy-init="true">     

 

<!-- 配置页面渲染器 -->

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

   <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

   <!-- 配置结果视图的前缀和后缀 -->

   <property name="prefix" value="/"/>

   <property name="suffix" value=".jsp"/>

    </bean>

    

    <bean id="messageSource"  class="org.springframework.context.support.ResourceBundleMessageSource">

    <property name="basename" value="i18n"></property>

</bean>

 

   <mvc:annotation-driven   />  <!-- 基于Schema-based XML的配置定义模式 -->

    <context:component-scan base-package="com.yirong.controller" />

    <mvc:default-servlet-handler/>

</beans>

 

 

User:

package com.yirong.controller.annotation;

 

import java.util.Date;

 

import javax.validation.constraints.Past;

import javax.validation.constraints.Size;

 

import org.hibernate.validator.constraints.Email;

import org.hibernate.validator.constraints.NotEmpty;

import org.springframework.format.annotation.DateTimeFormat;

 

public class User {

private Integerid;

@NotEmpty

private String name;

private Integerage;

private String tel;

@Email(message="邮箱格式错误")

private String email;

@Past //生日应该是一个之前的时间 ,past就表示是之前

@DateTimeFormat(pattern ="yyyy-MM-dd")

private Datebirth;

public Integer getId() {

return id;

}

public void setId(Integerid) {

this.id =id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name =name;

}

public Integer getAge() {

return age;

}

public void setAge(Integerage) {

this.age =age;

}

public String getTel() {

return tel;

}

public void setTel(String tel) {

this.tel =tel;

}

public String getEmail() {

return email;

}

public void setEmail(String email) {

this.email =email;

}

public Date getBirth() {

return birth;

}

public void setBirth(Datebirth) {

this.birth =birth;

}

@Override

public String toString() {

return "User [id=" +id +", name=" +name +", age=" + age +", tel=" +tel + ", email=" +email +", birth="

+ birth +"]";

}

}

 

 

Controller

package com.yirong.controller.annotation;

 

import java.io.IOException;

import java.io.Writer;

 

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.validation.Valid;

 

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.validation.BindingResult;

import org.springframework.validation.FieldError;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;

@RequestMapping("user")

@Controller //表示这个是一个Controller

public class OrderController {

@RequestMapping("/addUser")//请求此方法

public String add(@Valid Useruser,BindingResultbindResult,Modelmodel) {

if (bindResult.getErrorCount() > 0){

System.out.println("验证异常");

for (FieldErrorerror:bindResult.getFieldErrors()){

System.out.println(error.getField()+" : "+error.getDefaultMessage());

}

}

System.out.println(user.toString());

return "wel";//视图的名称

}

}

 

页面

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>restful</title>

</head>

<body>

添加用户 jsr 303:<br />

 <form action="/springMvcTest/user/addUser" method="post">

 名称:<input type="text" name="name" /><br />

 年龄:<input type="text" name="age" /><br />

 电话:<input type="text" name="tel" /><br />

 生日:<input type="text" name="birth" /><br />

 email:<input type="text" name="email" /><br />

 <input type="submit" value="提交" /><br />

 </form><br /><br />

</body>

</html>

 

效果:

验证异常

email : 邮箱格式错误

name : 不能为空

birth : 需要是一个过去的时间

User [id=null, name=, age=1, tel=1, email=a, birth=Tue Oct 10 00:00:00 CST 2017]

 

Json

Spring mvc对json也有很好的支持,需要下载jar

Jackson下载   http://wiki.fasterxml.com/JacksonDownload

导入jar包

jackson-annotations-2.8.0.jar

jackson-core-2.8.1.jar

jackson-databind-2.8.5.jar

 

配置文件复制”spring mvc 注解开发第4点的配置文件”

页面

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>restful</title>

</head>

<body>

<script type="text/javascript" src="../jquery-1.10.2.js" ></script>

<script type="text/javascript">

$(function(){

$('#testJsonId').click(function (){

$.post("/springMvcTest/order/testJson",{

                 },function(data){

  console.log(data);

});

});

});

</script>

<br />

testjson:

<button id="testJsonId">testjson</button>

<br />

</body>

</html>

 

Controlller

package com.yirong.controller.annotation;

 

import java.io.IOException;

import java.io.Writer;

import java.util.ArrayList;

import java.util.List;

 

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.validation.Valid;

 

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.ResponseBody;

@RequestMapping("order")

@Controller //表示这个是一个Controller

public class OrderController {

@ResponseBody

@RequestMapping("/testJson")//请求此方法

public List<Order> testJson() {

List<Order> list =new ArrayList<>();

Order o =new Order();

o.setOrderName("a");

Order o2 =new Order();

o2.setOrderName("b");

list.add(o);

list.add(o2);

return list; 

}

}

 

效果:

两个对象的值,正常拿到了

 

HttpMessageConverter<T>

HttpMessageConverter会将spring mvc框架的返回结果以out对象输出到客户端,只需要加上@responseBody的注解即可自动的用HttpMessageConverter进行转换处理

 

 


 

 

 

 

 

HttpMessageConverter的@ResponseBody文件上传

Controller

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.ResponseBody;

@RequestMapping("order")

@Controller //表示这个是一个Controller

public class OrderController {

@ResponseBody

@RequestMapping("/testh")

public String testh(@RequestBodyStringbody){

System.out.println(body);

return "aa";

}

}

 

页面:

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>restful</title>

</head>

<body> 

<br />

文件上传:

<form action="/springMvcTest/order/testh" method="POST" enctype="multipart/form-data" >

file:<input type="file" name="file" /><br />

desc:<input type="text" name="desc" /><br />

<input type="submit" value="submit"/>

</form>

<br />

</body>

</html>

 

运行结果:

 

 

响应到页面的文字:

 

 

文件下载

 

webContent/files/下放一个文件abc.txt,模拟文件下载

Controller

 

 

页面:

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<html>

<head>

<title>restful</title>

</head>

<body> 

<br />

文件下载:

 <a href=”testResponseEntity”>test 文件下载</a>

<br />

</body>

</html>

 

 

自己写

文件上传和下载

package com.yirong.annoation;

 

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

 

import javax.servlet.ServletContext;

import javax.servlet.http.HttpSession;

 

import org.springframework.http.HttpHeaders;

import org.springframework.http.HttpStatus;

import org.springframework.http.ResponseEntity;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.multipart.MultipartFile;

 

@Controller

@RequestMapping("/jsr")

public class File {

 

/**

 * 文件上传

 * @param desc

 * @param file

 * @return

 */

@RequestMapping("/uploadFile")

public String uploadFile(@RequestParam("desc") String desc,@RequestParam("file") MultipartFilefile){

System.out.println("文件描述:"+desc);

System.out.println("文件名称:"+file.getOriginalFilename());

try {

InputStream input =file.getInputStream();

BufferedReader buff =new BufferedReader(new InputStreamReader(input));

String str;

System.out.println("文件内容如下:");

while((str =buff.readLine()) !=null){

System.out.println(str);

}

} catch (IOExceptione) {

e.printStackTrace();

}

return "jsr/list";

}

/**

 * 文件下载

 * @param session

 * @return

 * @throws IOException

 */

@RequestMapping("/testResponseEntity")

public ResponseEntity<byte[]> restResponseEntity(HttpSessionsession,StringfileName)throws IOException{

byte[]body=null;

String name =new String(fileName.getBytes("iso-8859-1"),"utf-8");

ServletContext context=session.getServletContext();

System.out.println(name);

InputStream in=context.getResourceAsStream("/file/"+name);

body=new byte[in.available()];

in.read(body);

HttpHeaders headers=new HttpHeaders();

headers.add("Content-Disposition","attachment;filename="+new String(name.getBytes(),"iso-8859-1"));

HttpStatus status=HttpStatus.OK;

ResponseEntity<byte[]>response=new ResponseEntity<byte[]>(body,headers,status);

return response;

}

}

 

页面:

    文件上传:

    <form action="<%=request.getContextPath()%>/jsr/uploadFile" method="POST" enctype="multipart/form-data" >

file:<input type="file" name="file" /><br />

desc:<input type="text" name="desc" /><br />

<input type="submit" value="submit"/>

</form>

    <hr>

     <a href="<%=request.getContextPath()%>/jsr/testResponseEntity?fileName=罗.txt">文件下载</a><br/>  要下载的文件必须放置在Webcontent下

     <a href="<%=request.getContextPath()%>/jsr/testResponseEntity?fileName=弦子-天真.mp3">弦子 -天真.mp3</a>

     <br/>

     <hr>

 

package com.yirong.annoation;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

 

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.multipart.MultipartFile;

import org.springframework.web.servlet.ModelAndView;

 

@Controller

public class FileUploadController {

 

/*

 * SpringMVC中的文件上传

 * @第一步:由于SpringMVC使用的是commons-fileupload实现,故将其组件引入项目中

 * @这里用到的是commons-fileupload-1.2.1.jar和commons-io-1.3.2.jar

 * @第二步:spring-mvc中配置MultipartResolver处理器。可在此加入对上传文件的属性限制

 *  <bean id="multipartResolver"  

 *  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

 * <!-- 设置上传文件的最大尺寸为10MB -->  

 *<property name="maxUploadSize">  

 *<value>10000000</value>  

 * </property>  

 * </bean>

 * 第三步:在Controller的方法中添加MultipartFile参数。该参数用于接收表单中file组件的内容

 *第四步:编写前台表单。注意enctype="multipart/form-data"以及<input type="file" name="****"/>

 *  如果是单个文件 直接使用MultipartFile 即可

 */ 

@RequestMapping("/upload")

public ModelAndView upload(Stringname,

//上传多个文件

@RequestParam("file") MultipartFile[]file,

HttpServletRequest request)throws IllegalStateException,IOException {

//获取文件 存储位置

String realPath =request.getSession().getServletContext().getRealPath("/uploadFile");

File pathFile =new File(realPath);

if (!pathFile.exists()) {

//文件夹不存 创建文件

pathFile.mkdirs();

}

for (MultipartFilef :file) {

System.out.println("文件类型:"+f.getContentType());

System.out.println("文件名称:"+f.getOriginalFilename());

System.out.println("文件大小:"+f.getSize());

System.out.println(".................................................");

//将文件copy上传到服务器

f.transferTo(new File(realPath +"/" +f.getOriginalFilename()));

 //FileUtils.copy

}

//获取modelandview对象

ModelAndView view =new ModelAndView();

view.setViewName("redirect:index.jsp");

return view;

}

@RequestMapping(value ="download")  

public ModelAndView download(HttpServletRequestrequest,HttpServletResponseresponse)throws Exception {  

        //String storeName = "Spring3.xAPI_zh.chm";  

String storeName="房地.txt";

String contentType ="application/octet-stream";  

FileUploadController.download(request,response,storeName, contentType);  

return null;  

}  

      //文件下载 主要方法

public static void download(HttpServletRequestrequest, HttpServletResponseresponse,

String storeName, StringcontentType )throws Exception {  

request.setCharacterEncoding("UTF-8");  

BufferedInputStream bis =null;  

BufferedOutputStream bos =null;  

//获取项目根目录

String ctxPath =request.getSession().getServletContext().getRealPath("");  

//获取下载文件露肩

String downLoadPath =ctxPath+"/uploadFile/"+storeName;  

//获取文件的长度

long fileLength =new File(downLoadPath).length();  

//设置文件输出类型

response.setContentType("application/octet-stream");  

response.setHeader("Content-disposition","attachment; filename="  

+ new String(storeName.getBytes("utf-8"),"ISO8859-1"));

//设置输出长度

response.setHeader("Content-Length", String.valueOf(fileLength));  

//获取输入流

bis = new BufferedInputStream(new FileInputStream(downLoadPath));  

//输出流

bos = new BufferedOutputStream(response.getOutputStream());  

byte[]buff =new byte[2048];  

int bytesRead;  

while (-1 != (bytesRead =bis.read(buff, 0,buff.length))) {  

bos.write(buff, 0,bytesRead);  

}  

//关闭流

bis.close();  

bos.close();  

}  

}

国际化

在配置文件中添加:

 <bean id="messageSource"  class="org.springframework.context.support.ResourceBundleMessageSource">

    <property name="basename" value="i18n"></property>

</bean>

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>

 

Controller

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.support.ResourceBundleMessageSource;

import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping("order")

@Controller //表示这个是一个Controller

public class OrderController {

   @Autowired

private ResourceBundleMessageSourcemessageSource;

@RequestMapping("/testI18n") 

public String testI18n(Localelocale){

String val =messageSource.getMessage("i18n.username",null,locale);

System.out.println(val);

return "i18n";

}

}

 

添加配置文件i18n_zh_CN.properties到src下( unicode)

#用户名

i18n.username=\u7528\u6237\u540D 

#密码

i18n.password=\u5BC6\u7801

i18n_en_US.properties

i18n.username=username

i18n.password=password

 

页面相用fmt

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>   

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>  

<html>

<head>

<title>springmvc </title>

</head>

<body>

 <fmt:message key="i18n.username"></fmt:message>

 <br />

 

 <a href="/springMvcTest/order/testI18n" >testI18n </a>

  </body>

</html>

 

效果:

当请求testI18n时,打应的就是资源文件中的相应的国际化资源内容

 

 

:在页面如果需要国际化和数据格式化,则需要用到jstl的fmt标签(spring mvc暂时没有提供标签)

 

页面中英文切换

页面:

<%@ page language="java" contentType="text/html; charset=utf-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>   

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>  

<html>

<head>

<title>springmvc </title>

</head>

<body>

 <fmt:message key="i18n.username"></fmt:message>

 <br />

 

 <a href="/springMvcTest/order/testI18n?locale=zh_CH" >testI18n中文</a>

  <a href="/springMvcTest/order/testI18n?locale=en_US" >testI18n英文</a>

</body>

</html>

 

 

配置文件中添加:

 

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">

<property name="basename" value="i18n"></property>

</bean>

<bean id="localeResolver"  class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>

 <mvc:interceptors>

<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>

</mvc:interceptors> 

 

 

效果:

 

 

 

 

 

 

 

 

 

 

Spring mvc文件上传2

导入依赖的jar

commons-fileupload-1.3.1.jar

commons-io-2.2.jar

 

在配置文件中添加:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

<property name="defaultEncoding" value="utf-8"></property>

<property name="maxUploadSize" value="10240"></property>

</bean>

 

Controller

@RequestMapping("/testupload")

public String testupload(@RequestParam("desc") String desc,

@RequestParam("file") MultipartFilefile){

System.out.println(desc);

System.out.println(file.getOriginalFilename());

try {

System.out.println(file.getInputStream());

} catch (IOExceptione) {

e.printStackTrace();

}

return "wel";

}

 

 

页面添加内容

<br />

文件上传2:

<form action="/springMvcTest/order/testupload" method="POST" enctype="multipart/form-data">

file:<input type="file" name="file" /><br />

desc:<input type="text" name="desc" /><br />

<input type="submit" value="submit"/>

</form>

 

效果:

 

 

 

自定义拦截器

spring mvc 框架中要自定义拦截就要实现HandlerInterceptor:

package com.yirong.controller.annotation;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;

import org.springframework.web.servlet.ModelAndView;

public class FirstInterceptorimplements HandlerInterceptor{

/**

 * 此方法会在controller的目标方法调用前被调用 ,如果返回false则拦截器的后面两个方法和目标方法都不会再调用,

      可以做权限,日志,事务等功能

 */

@Override

public boolean preHandle(HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler)

throws Exception {

System.out.println("preHandle ");

return true; 

}

    /**

 * 调用目标方法之后,渲染视图之前被调用 可以对视做出更改,或修改请求域

 */

@Override

public void postHandle(HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler,

ModelAndView modelAndView)throws Exception {

System.out.println("postHandle ");

}

    /**

 * 渲染视图之后被调用  可以做释放资源

 */

@Override

public void afterCompletion(HttpServletRequestrequest, HttpServletResponseresponse, Objecthandler, Exceptionex)

throws Exception {

System.out.println("afterCompletion ");

}

}

 

在配置文件中添加配置

 

 <mvc:interceptors>

<!--自定义拦截器 -->

 <bean class="com.yirong.controller.annotation.FirstInterceptor"></bean>

</mvc:interceptors> 

 

 

写一个controller这里使用JSR 303的例子来调用一下,

访问连接:

http://localhost:8080/springMvcTest/order/addUser

 

效果:

 

 

这样拦截器就已经起效果了

 

 

 

 

指定url 用指定的拦截器

再创建一个拦截器SecondInterceptor

<mvc:interceptors>

 <!--自定义拦截器 -->

 <bean class="com.yirong.controller.annotation.FirstInterceptor"></bean>

 <mvc:interceptor> <!--表示/addUser 用拦截器:SecondInterceptor-->

 <mvc:mapping path="/addUser"/>

 <bean class="com.yirong.controller.annotation.SecondInterceptor"></bean>

 </mvc:interceptor> 

</mvc:interceptors> 

 

Spring mvc拦截器执行顺序:

 

 

当后面的拦截器返回false时直接执行前一个拦截器的afterCompletion方法,流程结束

 

异常处理

DispatcherServlet会默认装配HandlerExceptionResolver,如果spring mvc中没有配置<mvc:annotation-driven/>配置,那么框架会装载:

AnnotationMethodHandlerExceptionResolver,ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver

如果使用了<mvc:annotation-driven/>配置,

那么框架会装载:ExceptionHandlerExceptionResolver,ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver来处理异常

重点:ExceptionHandlerExceptionResolver

 

ExceptionHandlerExceptionResolver主要用@ExceptionHandler注解定义异常处理方法

@ExceptionHandler定义的异常处理方法有优先级问题,优先使用相对应的异常,如果没有就找抛出的异常的父类,并且不能同时配置多个完全相同的异常处理方法,比如:同时在多个方法标注:@ExceptionHandler({ArrayIndexOutOfBoundsException.class}),或不能同时在多个方法上只标注:@ExceptionHandler

,如果ExceptionHandlerExceptionResolver在目标controller中找不到@ExceptionHandler注解定义的方法,那么就会去找用@ControllerAdvice注解的类,并找这个类中的用@ExceptionHandler注解的方法来处理异常

:如果希望将异常显示到页面去,那么只能用ModelAndView,因为用@ExceptionHandler注解的方法不能用Map作为入参 

 

Controller

 

package com.yirong.controller.annotation;

 

import java.io.IOException;

import java.io.Writer;

import java.util.ArrayList;

import java.util.Date;

import java.util.List;

import java.util.Locale;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.servlet.ModelAndView;

@RequestMapping("order")

@Controller //表示这个是一个Controller

public class OrderController { 

@ExceptionHandler({ArithmeticException.class})

public ModelAndView handlerException(Exceptionex){

System.out.println("异常:"+ex);

ModelAndView mv =new ModelAndView();

mv.setViewName("error");

mv.addObject("exception",ex);

return mv;

}

@ExceptionHandler({RuntimeException.class})

public ModelAndView handlerException1(Exceptionex){

System.out.println("异常1:"+ex);

ModelAndView mv =new ModelAndView();

mv.setViewName("error");

mv.addObject("exception",ex);

return mv;

}  

@RequestMapping("/testExcep")

public StringtestExcep(@RequestParam("i") Integeri){

 System.out.println(10/i);

return "wel";

}

}

 

页面添加一个连接

 <a href="/springMvcTest/order/testExcep?i=10">异常</a>

 

当请求此连接,给参数为0的时候,就会出现异常,

出异常的时候,因为有配置@ExceptionHandler,则异常会默认被用此注解的方法去处理

:@ExceptionHandler可以指定异常的类型,例子中添加了两个异常方法,一个是RuntimeException类型的异常方法,

一个是ArithmeticException类型的异常方法,那么当testExcep方法出异常后会调用被标注为ArithmeticException异常的方法来处理异常,

 

如果目标controller中没有异常处理方法,那么怎么处理异常?

Spring mvc框架提供了一个异常处理方式,可以将异常处理方法写在一个指定类中,这个类需要用@ControllerAdvice注解,目标controller中没有异常处理方法时,就会找用@ControllerAdvice注解的类,并找这个类中的用@ExceptionHandler注解的方法来处理异常

 

 

package com.yirong.controller.annotation;

 

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.servlet.ModelAndView;

 

@ControllerAdvice

public class MyExceptionHandler {

 

@ExceptionHandler({ArithmeticException.class})

public ModelAndView handlerException(Exceptionex){

System.out.println("异常:"+ex);

ModelAndView mv =new ModelAndView();

mv.setViewName("error");

mv.addObject("exception",ex);

return mv;

}

@ExceptionHandler({RuntimeException.class})

public ModelAndView handlerException1(Exceptionex){

System.out.println("异常1:"+ex);

ModelAndView mv =new ModelAndView();

mv.setViewName("error");

mv.addObject("exception",ex);

return mv;

}

}

 

 

SimpleMappingExceptionResolver

了解

SimpleMappingExceptionResolver异常处理,ex为页面使用的对象在requestScope中

prop 表示配置发生指定异常去指定页面

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">

<property name="exceptionAttribute" value="ex"></property>

<property name="exceptionMappings">

<props>    

<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>

</props>

</property>

</bean>

SpringMVC数据转换 & 数据格式化 & 数据校验

 

 

Spring mvc 整合spring

 

使用注解,那么就需要在配置文件中配置扫描<context:component-scan base-package="指定扫描的包路径" />

Spring mvc需要配置,而spring的容器也需要配置,也就是配置bean的包.如果这两个配置有重复的话,那么容器将加载多次,这是不对的.

所以需要配置过滤:

spring mvc的配置文件中可以配置指定要扫描的包路径下的指定注解,在spring 中可以配置指定路径下不扫描指定注解

<context:component-scan base-package="com.yr" use-default-filters="false" >

<context:include-filter type="annotation" 

expression="org.springframework.stereotype.Controller"/> 

<context:include-filter type="annotation" 

expression="org.springframework.web.bind.annotation.ControllerAdvice"/>

</context:component-scan>

 

Spring配置文件中:

<context:component-scan base-package="com.yr" use-default-filters="false" >

<context:exclude-filter type="annotation" 

expression="org.springframework.stereotype.Controller"/> 

<context:exclude-filter type="annotation" 

expression="org.springframework.web.bind.annotation.ControllerAdvice"/>

</context:component-scan>