springMvc的总结:(推荐,总共有十五章)
http://www.cnblogs.com/liukemng/p/3751338.html
拦截器不拦截静态资源
http://www.cnblogs.com/banning/p/6195072.html
学习版本: 4.3.0
框架学起来比较简单
但也有难的地方,难是难在底层原理
用了框架之后,写代码就非常简单,因为框架会完成一部分代码,
我们只要按框架的规则去使用就可以了
学习框架的方法:
与学习初级基础有所不同,
基础学习都是学习基本语法,完成简单的案例,逐步理解面向对象的编程思想.
框架属于中高级的学习,要运用面向对象的进行编程,接口编程
能够自已完成业务.熟悉业务.能够架构一个项目,属性框架的原理
框架学习程度:
相用框架
理解框架原理、走源码
自己编写框架部分
Md1
Md2
Jsp/servlet 的 mvc回顾
当一个方法中有部分代码在不断重复时,抽取出来做一个方法
当很多类在操作同一段代码时,抽出来做一个类
当很多类在做同一类事情的时候,抽出来做一个jar包或做成框架
这就是框架
框架,替程序员完成一部分代码,从而提高开发效率
框架就是一个模板,
Web应用的框架:webwork,jsf, struts1, struts2,springmvc
Servlet:
将页面请求映射到java类,也就是后台
接收并处理页面提交的数据
调用业务逻辑方法处理业务结果,将数据封装准备渲染到页面
控制页面跳转
Mvc的V层:
将页面请求映射到java类,也就是后台
获取并封装好页面提交的数据
渲染数据到页面
控制页面跳转
http://repo.springsource.org/libs-release-local/org/springframework/spring
向下拉选中需要下载的版本。
点击相应需要下载的zip,window版本直接下zip即可
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. 拦截器
使用的人多,使用的公司多
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. 将渲染结果返回给客户端。
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启动的时候就加载
|
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">
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">bean>
<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"/>
<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. 请求结果
|
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>springmvcservlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<load-on-startup>1load-on-startup> servlet> <servlet-mapping> <servlet-name>springmvcservlet-name> <url-pattern>*.dourl-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"/>
<property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> bean>
<context:component-scan base-package="com.yirong.controller.annotation" /> beans> |
5. 效果:
|
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">
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">bean>
<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"/>
<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">helloControllerprop> 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">
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">bean>
<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"/>
<property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> bean>
<bean name="helloController" class="com.yirong.controller.HelloController">bean> beans> |
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(HttpServletRequest arg0, 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"; //默认转发 } |
1. 给controller添加一个构造方法,在启动时执行一次,而后访问时不会再执行
public HelloWorldController(){ System.out.println("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 |
|
要求表单中的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 |
|
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 |
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可以不需要
配置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):
|
Spring mvc 中解决乱码是通过CharacterEncodingFilter过滤器来解决的,因此需要在web.xml中配置。并且CharacterEncodingFilter主要是用于解决post请求的乱码,
get请求方式的乱码需要用到tomcat或jsp页面设置的方式进行解决
注:此配置需要配置在DispatcherServlet之前
<filter> <filter-name>CharacterEncodingFilterfilter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class> <init-param> <param-name>encodingparam-name> <param-value>utf-8param-value> init-param> filter> <filter-mapping> <filter-name>CharacterEncodingFilterfilter-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. 效果:
|
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风格:轻量级,安全,效率高
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可以修饰在类上面,表示指定的目录为这个类请求的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";//视图的名称 } }
|
效果:
|
此方式了解即可
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";//视图的名称 } } |
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, Model model) { 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>restfultitle> 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">
<filter> <filter-name>HiddenHttpMethodFilterfilter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class> filter> <filter-mapping> <filter-name>HiddenHttpMethodFilterfilter-name> <url-pattern>/*url-pattern> filter-mapping> <filter> <filter-name>CharacterEncodingFilterfilter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class> <init-param> <param-name>encodingparam-name> <param-value>utf-8param-value> init-param> filter> <filter-mapping> <filter-name>CharacterEncodingFilterfilter-name> <url-pattern>/*url-pattern> filter-mapping>
<servlet> <servlet-name>springmvcservlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class> <init-param> <param-name>contextConfigLocationparam-name> <param-value>classpath:springmvc.xmlparam-value> init-param> <load-on-startup>1load-on-startup> servlet> <servlet-mapping> <servlet-name>springmvcservlet-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> <context:component-scan base-package="com.yirong.controller.annotation" /> beans> |
在上面例子的类中添加以下方法:
@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>requestParamtitle> 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.
此注解与详解@RequestMapping的headers参数是一个意思,用法与@RequestMapping相同,表示指定请求头包含指定参数名.了解即可.
此注解可以让处理方法的入参绑定某个Cookies的值,表示是从cookies中取指定参数名称的值.
每一次请求都有一个JSESSIONID,那么我们可以通过@CookiesValue这个注解将JSESSIONID通过处理方法入参的方式获得
@RequestMapping(value="/testCookiesValue") public String testCookiesValue(@CookieValue(value="JSESSIONID") String sessionId, @RequestParam(value="age") Integerage, Model model) { 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>requestParamtitle> head> <body> <form action="/springMvcTest/testCookiesValue" method="post"> <input type="text" name="age" /> <input type="submit" value="提交" /> form> ${msg } body> html> |
效果:正常的取到cookies中的值
|
在前面已实现将对象做为参数传递到spring mvc的controller中,在传递的过程中,spring mvc
会将指定的参数名自匹配到pojo的属性名中,并且还会填充值到pojo的属性中.且支持级联属性.
注: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>restfultitle> 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> |
注: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>restfultitle> 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的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 原生apia> body> html> |
效果:
|
Spring mvc 会将模型数据对象中的数据添加到request对象中
原码:InternalResourceView.renderMergedOutputModel() -> AbstractView.exposeModelAsRequestAttributes()
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 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 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入参的方式处理模型数据在前面章节中已有详细例子.
如需在多个请求之间共享某个模型属性数据,则可以在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使用场景
解决问题:
在更新之前应该从数据中根据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 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)传给目标方法入参
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中
根据以上原理分析,注解了@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
1. 若项目中使用了jstl,则spring mvc会自动把视图由InternalResourceView转为JstlView
2. 如果使用了jstl的fmt标签则需要在spring mvc的配置文件中配置国际化资源文件
|
3. 如果希望直接响应通过spring mvc渲染的页面,可以使用
|
用于配置直接转发的页面,不需要经过controller,直接输入配置的/aa就会请求到wel视图
<mvc:view-controller path="/aa"view-name="wel" /> |
这样的请求方式适用于,有些页面不需要任何controller处理逻辑就要响应的页面
注:如果需要用
优雅的rest风格的资源url不希望带.html或.do等后缀,所以在web.xml中配置DispatcherServlet过滤请求时配置的是/,则spring mvc在捕获web容器的所有请求,包括静态资源的请求,如:js时也会将它们当成一个普通的请求处理,因此将不能在controller中找到请求而报404
解决问题:
在spring mvc的配置文件中添加一个<mvc:default-servlet-handler />
原理:
注:一般web应用服务器默认的servlet的名称都是default,如使用的web服务器的默认servlet名称不是default,则需要通过default-servlet-name属性显示的指定:
<mvc:default-servlet-handler default-servlet-name="servlet名称" />
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 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> |
还提供以下支持:
支持使用ConversionService实例对表单参数进行类型转换
支持使用@NumberFormatannotation.@DateTimeFormat注解完成数据类型的格式化
支持使用@Valid注解对javabean实例进行jsr 303验证
支持使用@RequestBody和@ResponseBody注解
由@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>restfultitle> 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 is java.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 @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>restfultitle> 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支持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 /> <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>restfultitle> 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] |
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>restfultitle> 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">testjsonbutton> <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 List Order o =new Order(); o.setOrderName("a"); Order o2 =new Order(); o2.setOrderName("b"); list.add(o); list.add(o2); return list; } } |
效果:
两个对象的值,正常拿到了 |
HttpMessageConverter会将spring mvc框架的返回结果以out对象输出到客户端,只需要加上@responseBody的注解即可自动的用HttpMessageConverter进行转换处理
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(@RequestBodyString body){ System.out.println(body); return "aa"; } } |
页面:
<%@ page language="java" contentType="text/html; charset=utf-8"%> <html> <head> <title>restfultitle> 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>restfultitle> 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">弦子 -天真.mp3a>
<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处理器。可在此加入对上传文件的属性限制
*
* class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
*
*
*
*
*
* 第三步:在Controller的方法中添加MultipartFile参数。该参数用于接收表单中file组件的内容
*第四步:编写前台表单。注意enctype="multipart/form-data"以及
* 如果是单个文件 直接使用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> |
效果:
|
导入依赖的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
效果:
|
这样拦截器就已经起效果了
再创建一个拦截器SecondInterceptor
<mvc:interceptors>
<bean class="com.yirong.controller.annotation.FirstInterceptor">bean> <mvc:interceptor> <mvc:mapping path="/addUser"/> <bean class="com.yirong.controller.annotation.SecondInterceptor">bean> mvc:interceptor> mvc:interceptors> |
当后面的拦截器返回false时直接执行前一个拦截器的afterCompletion方法,流程结束
DispatcherServlet会默认装配HandlerExceptionResolver,如果spring mvc中没有配置
AnnotationMethodHandlerExceptionResolver,ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver
如果使用了
那么框架会装载: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异常处理,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">errorprop> props> property> bean> |
使用注解,那么就需要在配置文件中配置扫描<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> |