一.springMVC配置文件
DispatcherServlet-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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!--
Spring MVC主要由DispatcherServlet、
处理器映射【找控制器】、
适配器【调用控制器的方法】、
控制器【业务】、
视图解析器、
视图组成。
-->
<!-- 配置 注解扫描位置 在编写的Controller中添加Controller注解即可-->
<context:component-scan base-package="com.miracle.web.controller"/>
<!-- 如果写了下面这个,那么 处理器映射器,处理器适配器 就可以不用配置 -->
<!--<mvc:annotation-driven/>-->
<!-- 配置 处理器映射器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<!-- 配置 注解处理器适配器来执行控制器的方法 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<!--配置json转换器,告诉springMVC使用jackson来转换数据-->
<property name="messageConverters">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</property>
</bean>
<!-- 配置 资源视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/views/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
二.controller编写
1 @RequestMapping 除了可以使用请求URL映射请求外,还可以使用请求方法,请求参数以及请求头映射请求
@RequestMapping的value,method,params以及heads分别表示请求URL,请求方法,请求参数以及请求头的映射条件,他们之间是与的关系,联合使用多个条件可以让请求映射更加精确化。
示例:
// 表示映射url为testMethod路径,接受的方式是post方法
@RequestMapping(value = "/testMethod", method = RequestMethod.POST)
params 和 headers 支持简单的表达式:
param1:表示请求必须包含名为param1的请求参数
!param1:表示请求不能包含名为param1的请求参数
param1!=value1:表示请求包含名为param1的请求参数,但其值不能为value1
{"param1=value1", "param2"}:请求必须包含名为param1 和 param2的两个请求参数,且param1参数的值必须为value1
// 表示请求路径是testParamsAndHeaders,必须有username参数,且age参数不为10,请求头必须含有参数Accept-Language
@RequestMapping(value = "/testParamsAndHeaders", params = {"username", "age!=10"}, headers = {"Accept-Language"})
2 @RequestMapping url映射还支持Ant风格的URL
Ant 风格资源地址支持3种匹配符:
- ?:匹配文件名中的一个字符
- *:匹配文件名中的任意字符
- **:**匹配多层路径
示例:
/user/*/createUser:匹配 /user/aaa/creatUser,/user/bbb/createUser 等URL
/user/**/createUser:匹配 /user/createUser,/user/aaa/bbb/createUser 等URL
/user/createUser??:匹配 /user/createUseraa,/user/createUserbb 等URL
3 @PathVariable 获取URL路径参数(使得springMVC支持REST风格)
REST风格介绍
REST:即 Representational State Transfer。资源表现层状态转化。是目前流行的一种互联网软件架构。它结构清晰,符合标准,
易于理解,扩展方便所以正得到越来越多网站的采用
资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本,一张图片,一首歌曲,一种服务,
总之就是一个具体的存在。可以用一个URL(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源(统一资源定位
符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URL就可以,因此URI即为每个资源的独一无二的标识符。
表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层,比如,文本可以用txt格式表现,也可以用HTML格式,
XML格式,JSON格式表现,甚至可以采用二进制格式。
状态转化(State Transfer):,每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有
的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"。二这种转化是建立
在表现成之上的,所以就是"表现成状态转化"。具体说,就是HTTP协议里面,四个表示操作方式的动词:GET,POST,PUT,
DELETE。他们分别对应四种基本操作:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源
示例:
/order/1 HTTP GET:得到id = 1 的order
/order/1 HTTP DELETE:删除id = 1 的order
/order/1 HTTP PUT:更新id = 1 的order
/order HTTP POST:新增order
HiddenHttpMethodFilter:浏览器form表单只支持GET和POST请求,而DELETE,PUT等method并不支持,
Spring3.0添加了一个过滤器,可以将这些请求转化为标准的http方法,使得支持GET,POST,PUT与DELETE请求
如何发送PUT请求和DELETE请求?
1.在xml中配置HiddenHttpMethodFilter过滤器
2.前端需要发送POST请求是,携带一个name="_method"的隐藏域,值为DELETE 或 PUT
3.在controller中 定义相应的方法,接收对应的请求(GET,POST,PUT,DELETE)
示例:
1.web.xml
<!--配置 org.springframework.web.filter.HiddenHttpMethodFilter
可以把POST请求转为 DELETE 或 PUT 请求,使SpringMVC支持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>
2.前端页面通过提交隐藏域告诉后台请求类型
<br>
<form action="/springmvc/testRest/1.do" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="TestRest PUT">
</form>
<br>
<form action="/springmvc/testRest/1.do" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="TestRest DELETE">
</form>
<br>
<form action="/springmvc/testRest.do" method="post">
<input type="submit" value="TestRest POST">
</form>
<br>
<a href="/springmvc/testRest/1.do">Test Rest Get</a>
<br>
3.controller
package com.miracle.springmvc.handlers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {
private static final String SUCCESS = "success";
@RequestMapping(value = "/testRest/{id}", method = RequestMethod.PUT)
public String testRestPut(@PathVariable("id") Integer id){
System.out.println("testRestPut" + id);
return SUCCESS;
}
@RequestMapping(value = "/testRest/{id}", method = RequestMethod.DELETE)
public String testRestDelete(@PathVariable("id") Integer id){
System.out.println("testRestDelete" + id);
return SUCCESS;
}
@RequestMapping(value = "/testRest", method = RequestMethod.POST)
public String testRestPost(){
System.out.println("testRestPost");
return SUCCESS;
}
@RequestMapping(value = "/testRest/{id}", method = RequestMethod.GET)
public String testRestGet(@PathVariable("id") Integer id){
System.out.println("testRestGet" + id);
return SUCCESS;
}
}
通过注解 @PathVariable 可以将URL中路径参数绑定到控制器方法的参数中
例如
@RequestMapping("testPathVariable/{id}")
public String testPathVariable(@PathVariable("id") Integer id){
System.out.println(id);
return SUCCESS;
}
UserController
package com.miracle.web.controller;
import com.miracle.model.User;
import com.miracle.model.UserExt;
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.RequestParam;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@SuppressWarnings("all")
@Controller // 声明这个Controller 相当于spring中配置一个bean
@RequestMapping("/user") // 绑定路径1
public class UserController{
/**
* RequestMapping 参数的写法
*
* RequestMapping(“list”)
* RequestMapping(“/list.do”)
* RequestMapping(value=”/list.do”)
* RequestMapping(value = "/list3",method=RequestMethod.POST) 只能使用POST方法访问
* RequestMapping(value = "/list3",method=RequestMethod.Get) 只能使用GET方法访问
*/
@RequestMapping("/list") // 绑定路径2 最终浏览器访问的路径是:绑定路径1 + 绑定路径2
public String list(Model model){ // 参数model用来存储数据返回给页面
List<User> userList = new ArrayList<>();
User user1 = new User("11", "11");
User user2 = new User("22", "22");
User user3 = new User("33", "33");
userList.add(user1);
userList.add(user2);
userList.add(user3);
model.addAttribute("userList", userList);
// 返回的字符串为服务器资源路径(返回字符串还要拼接 资源视图解析器 配置的前缀和后缀)
return "user/userlist";
}
@RequestMapping("/toRegister")
public String toRegister(){
return "user/register";
}
/**
* 第一种接收表单参数的方式
* 在方法中定义参数接收表单提交的数据,要求表单提交的name属性和参数名一致
* @return
*/
@RequestMapping("/register1")
public String register1(String username, String password, String gender, int age, Date birthday, String[] hobbysIds ){
// 在方法中定义参数用来接收前台传入的参数
/*
可以接收get请求 通过?username=aaa,password=bbb
也可以接收post请求的参数
*/
// 当请求是restful风格的url时,如 edit/5
/*
此时要想接收参数
注解的写法 @RequestMapping("/edit/{id}")
方法参数的写法 public String edit(@PathVariable int id){
}
*/
System.out.println(username);
System.out.println(password);
System.out.println(gender);
System.out.println(age);
System.out.println(birthday);
System.out.println(Arrays.toString(hobbysIds));
return "user/info";
}
/**
* 第二种接收表单参数的方式
* 在方法中定义POJO接收表单提交的数据,要求表单提交的name属性和POJO字段名一致
* @return
*/
@RequestMapping("/register2")
public String register2(User user){
System.out.println(user);
return "user/info";
}
/**
* 第三种接收表单参数的方式(JavaBean嵌套JavaBean)
* 在方法中定义POJO接收表单提交的数据,要求表单提交的name属性和POJO字段名一致
* @return
*/
@RequestMapping("/register3")
public String register3(UserExt userExt){
// 这里前端name属性为 user.username user.password
System.out.println(userExt);
return "user/info";
}
/**
* 第四种接收表单参数的方式(用List接收form数据)
* @return
*/
@RequestMapping("/register4")
public String register4(UserExt userExt){
// 这里前端name属性为 user.username user.password
System.out.println(userExt.getUserList());
return "user/info";
}
/**
* 第五种接收表单参数的方式(用map接收form数据)
* @return
*/
@RequestMapping("/register5")
public String register5(UserExt userExt){
// 这里前端name属性为 user.username user.password
System.out.println(userExt.getMap());
return "user/info";
}
/**
* restful风格请求处理 以及 springMVC请求转发,重定向
* @return
*/
@RequestMapping("/edit/{id}")
public String restful(@PathVariable int id, Model model){
System.out.println("id:"+id);
model.addAttribute("id", id);
// 重定向:forward + path
// 请求转发:redirect + path
return "forward:/user/forwardDemo.do";
// return "redirect:/user/redirectDemo.do";
}
@RequestMapping("/forwardDemo")
public String forward(){
return "user/forward";
}
@RequestMapping("/redirectDemo")
public String redirect(){
return "user/redirect";
}
/**
* 对方法参数进行一些说明 RequestParam
* value:参数名称
* defaultValue:默认值
* required:参数是否必须有值,如果为true,参数又为空,会报错
*/
@RequestMapping("/requestParamDemo")
public String requestParamDemo(@RequestParam(value = "id", required = true, defaultValue = "30") int id){
System.out.println(id);
return "user/info";
}
/*
SpringMVC还可以接收请求头参数
通过注解 @RequestHeader
用法同上
*/
@RequestMapping("/testRequestHeader")
public String testRequestHeader(@RequestHeader(value = "Accept-Language") String al){
System.out.println(al);
return SUCCESS;
}
}
StudentController
package com.miracle.web.controller;
import com.miracle.model.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@SuppressWarnings("all")
@Controller // 声明这个Controller 相当于spring中配置一个bean
@RequestMapping("/student") // 绑定路径1
public class StudentController {
@RequestMapping("/reg")
public String reg(){
return "student/add";
}
/**
* 接收,返回json数据
* @RequestBody:告诉框架把接收到的json数据转换成JavaBean对象(注意RequestBody后面只能跟javaBean)
* RequestMapping:将对象转换成json字符串返回
* @return
*/
@RequestMapping("/save")
@ResponseBody
public Student save(@RequestBody Student student){
System.out.println(student);
return student;
}
}
4 除了上述接收前端表单的传参,SpringMVC中controller类中的方法可以传入一些ServletAPI
例如:HttpServletRequest,HttpServletResponse,HttpSession等
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request, HttpServletResponse response){
System.out.println(request);
System.out.println(response);
return SUCCESS;
}
5 SpringMVC提供了以下几种途径向前端页面返回数据
- 1.ModelAndView
原理:SpringMVC会把ModelAndView中的mode的数据放到request域对象中,数据在单个请求中有效
controller写法
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
// 构造方法中指定视图名字
ModelAndView modelAndView = new ModelAndView(SUCCESS);
// 添加模型数据到modelAndView中
modelAndView.addObject("time", new Date());
return modelAndView;
}
jsp写法
time:${time}
- 2.在controller方法的参数中添加Map或Model参数
原理:SpringMVC会把Map,Model中的数据放到request域对象中,数据在单个请求中有效
传Map和Model的用法相同
@RequestMapping("/testMapAndModel")
public String testMapAndModel(Model model){
model.addAttribute("names", Arrays.asList("Tom", "Jerry", "Mike"));
return SUCCESS;
}
- 3.使用 @SessionAttributes 注解,将数据放到session域对象中
原理:SpringMVC会把Map,Model中的数据同时放到request和session域对象中,数据在整个session中有效
/*
1.@SessionAttributes注解只能修饰类
2.value = {"user"} 属性指定了下面模型中哪些key是同时放到request和session中的
3.types = {Date.class} 属性指定了下面模型中哪些value是同时放到request和session中的
*/
@SessionAttributes(value = {"user"},types = {Date.class})
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {
private static final String SUCCESS = "success";
@RequestMapping("/testSessionAttributes")
public String testSessionAttributes(Model model){
User user = new User("username", "password", "email", "age");
// 通过 @SessionAttributes 注解指定key,将user同时放到request和session域中
model.addAttribute("user", user);
// 通过 @SessionAttributes 注解指定value的类型,将time的值同时放到request和session域中
model.addAttribute("time", new Date());
// 由于没有指定,所以name的值只是方法request域中
model.addAttribute("name", "miracle");
return SUCCESS;
}
}
注意
当使用 @SessionAttributes 注解 将 controller 方法里面的数据向session和request中存时,如果@SessionAttributes的value值 和 controller 方法 参数 POJO类名的首字母小写 相同的话,会报错
// 这里想将user放入request和session中
@SessionAttributes(value = {"user"})
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {
private static final String SUCCESS = "success";
@RequestMapping("/testform")
public String testViewAndViewResolver(Model model, User user){
// 这里想将user放入request和session中
// 由于@SessionAttributes的value值(user)和 POJO(User类)的首字母小写一样,会报错
model.addAttribute("user", user);
System.out.println("testform");
return SUCCESS;
// 解决办法
// @SessionAttributes(value = {"user"}) 改为 @SessionAttributes(value = {"user1"})
// model.addAttribute("user", user); 改为 model.addAttribute("user1", user);
}
}
三.视图与视图解析器
1.SpringMVC 视图解析流程
2.SpringMVC 视图和视图解析器概念
3.mvc:view-controller标签
如果发送的请求不想通过controller,只想直接地跳转到目标页面,这时候就可以使用mvc:view-controller标签
在springMVC配置文件中添加
<mvc:view-controller path="/hello" view-name="hello"></mvc:view-controller>
<mvc:annotation-driven />
path=”/hello” 就是你访问的路径(相当于RequestMapping(“/hello”))
view-name=”hello”是你所要的视图(如hello.jsp,相当于return “hello”) 配置了这个后对于/hello请求,就会直接交给dispatcherServlet,然后使用ViewResolver进行解析。
也可以配置成重定向或者转发:
<mvc:view-controller path="/index" view-name="redirect:hello"></mvc:view-controller>
4.springMVC配置其他视图实现(View)
- 这里我以编写一个自定义的视图实现,来演示自定义视图实现的流程
(1)在springMVC配置文件中配置视图解析器,其中第二个 BeanNameViewResolver 是额外配置的
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.miracle.springmvc"></context:component-scan>
<!-- 配置视图解析器:如何把handler 方法返回值解析为实际的物理视图 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/views/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
<!--
配置视图 BeanNameViewResolver 解析器:
作用:当controller方法返回字符串,这个解析器拿着字符串,去IOC容器中匹配,找对应的View对象
-->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<!--
通过order属性来定义视图解析器的优先级,order值越小优先级越高,
查看上面视图解析器的源码,发现其order值是int类型的最大值,
因此 BeanNameViewResolver 优先级高于 InternalResourceViewResolver
功能越泛用的,order越大,优先级越低。功能越专一的,order越小,优先级越高
-->
<property name="order" value="100"></property>
</bean>
(2)编写自定义的视图,需要实现SpringMVC提供View接口
package com.miracle.springmvc.views;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.View;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Map;
// 实现View接口
@Component // 向IOC容器中注册视图
public class HelloView implements View {
// 返回内容类型
@Override
public String getContentType() {
// 这里设定渲染后返回给浏览器内容的类型
return "text/html";
}
// 实现渲染视图方法
@Override
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 这里定义向浏览器展示内容的逻辑
response.getWriter().print("hello view, time:" + new Date());
}
}
(3)编写controller
package com.miracle.springmvc.handlers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {
private static final String SUCCESS = "success";
@RequestMapping("/testView")
public String testView() {
System.out.println("testView");
// 这里由于配置了 BeanNameViewResolver ,
// 这个解析器会根据方法返回的字符串,去IOC容器中找View
return "helloView";
}
}
(4)测试
发送请求:/springmvc/testView.do
被controller拦截,根据视图解析器转发的到View对象上
View对象渲染,返回结果
如果想在页面展示Excel,PDF,报表,JSON之类的,可以百度具体的View实现类,替换 示例中的HelloView 即可
四.关于重定向 和 请求转发
1.重定向 redirect 示例
controller
package com.miracle.springmvc.handlers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {
private static final String SUCCESS = "success";
// 拦截 /springmvc/testRedirect.do的请求,
// 接收请求后重定向到 /springmvc/testRedirect1.do
@RequestMapping("/testRedirect")
public String testRedirect(){
System.out.println("testRedirect");
// 这里redirect后面的路径,跟的是下一个controller方法拦截的路径
return "redirect:/springmvc/testRedirect1.do";
}
@RequestMapping("/testRedirect1")
public String testRedirect1(){
System.out.println("testRedirect1");
return SUCCESS;
}
}
jsp
<a href="/springmvc/testRedirect.do">testRedirect</a>
2.请求转发 forward 示例
controller
package com.miracle.springmvc.handlers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {
private static final String SUCCESS = "success";
// 拦截 /springmvc/testForward.do的请求,
// 接收请求后转发到 拦截 路径/springmvc/testForward1.do 的controller 方法来处理
@RequestMapping("/testForward")
public String testRedirect(){
System.out.println("testForward");
return "forward:/springmvc/testForward1.do";
}
@RequestMapping("/testForward1")
public String testRedirect1(){
System.out.println("testForward1");
return SUCCESS;
}
}
jsp
<a href="/springmvc/testForward.do">testForward</a>
五.处理静态资源
只需要在springMVC配置文件中增加
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<mvc:annotation-driven></mvc:annotation-driven>
六.数据转换,数据格式化,数据校验
1.创建自定义的数据转换器
假设有如下需求:
页面上有input框,用户只要按要求输入 username-password-age-datetime 格式,
就会自动转换成POJO对象
示例
1.jsp
<form action="/testConversionServiceConverer" method="post">
请按照 username-password-age-datetime 格式 输入用户信息
<br>
userinfo:<input type="text" name="userinfo">
<br>
<input type="submit" value="submit">
</form>
2.controller
@Controller
public class UserController {
@RequestMapping("/testConversionServiceConverer")
public String userConverter(@RequestParam(value = "userinfo")Userinfo userinfo){
System.out.println(userinfo);
return "success";
}
}
3.converter
package com.miracle.converters;
import com.miracle.orm.Userinfo;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
// 自定义转换类,需要实现 Converter 接口,注册到IOC容器中
@Component // 这里的接口泛型是String, Userinfo,是因为我们要做String 转 Userinfo
public class UserinfoConverter implements Converter<String, Userinfo> {
// 这里写转换逻辑
@Override
public Userinfo convert(String source) {
if (source != null){
// username-password-age-datetime 格式
String [] vals = source.split("-");
if (vals != null && vals.length == 4){
String username = vals[0];
String password = vals[1];
Integer age = Integer.parseInt(vals[2]);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
Date datetime = null;
try {
datetime = sdf.parse(vals[3]);
} catch (ParseException e) {
e.printStackTrace();
}
Userinfo userinfo = new Userinfo(username, password, age, datetime);
System.out.println(source + "--convert--" + userinfo);
return userinfo;
}
return null;
}
return null;
}
}
4.springMVC配置文件
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<!-- 配置ConversionService -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<!--由于这个属性接收的是set集合,可以配置多个转换器同时工作-->
<property name="converters">
<set>
<ref bean="userinfoConverter"></ref>
</set>
</property>
</bean>
2.使用springMVC的数据转换器
现在前端提交的数据有日期参数需要转换
date:1992-01-27
这两个在pojo里面以 Date 存储(注意这里Date必须是 java.sql.Date)
如需要格式化,只需在pojo对应字段添加格式化注解
package com.miracle.orm;
import org.springframework.format.annotation.DateTimeFormat;
import java.sql.Date;
public class Miracle {
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date date;
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public String toString() {
return "Miracle{" +
"date=" + date +
'}';
}
}
七.mvc:annotation-driven 作用
结论,开发的时候要在springMVC配置文件中加上 mvc:annotation-driven
八.处理JSON
1.导入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.10</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.10</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.10</version>
</dependency>
2.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<script type="text/javascript" src="scripts/jquery-1.12.4.js"></script>
<script type="text/javascript">
$(function () {
$("#testjson").click(function () {
var data = {"username":"miracle","password":"123456","age":27,"date":"2017-09-09 12:23:09"};
$.ajax({
type : 'POST',
contentType : 'application/json;charset=utf-8',
url : this.href,
dataType : 'json',
data : JSON.stringify(data),
success : function(data) {
console.log(data);
},
error : function(XMLHttpRequest, textStatus, errorThrown) {
alert("出现异常,异常信息:"+textStatus,"error");
}
});
return false;
})
})
</script>
</head>
<body>
<h2>Hello World!</h2>
<a href="/testJson" id="testjson">Test Json</a>
</body>
</html>
3.pojo
package com.miracle.orm;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
public class Userinfo {
private String username;
private String password;
private Integer age;
// 这里由于前台传过来的数据有时间,这里格式化
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date date;
public Userinfo() {
}
public Userinfo(String username, String password, Integer age, Date date) {
this.username = username;
this.password = password;
this.age = age;
this.date = date;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public String toString() {
return "Userinfo{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
", date=" + date +
'}';
}
}
4.controller
package com.miracle.controller;
import com.miracle.orm.Userinfo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
public class UserController {
//@RequestBody:接收json数据并转换成pojo对象
//@ResponseBody:响应json数据,把java对象转换成json并响应
@ResponseBody
@RequestMapping("/testJson")
public List<Userinfo> testJson(@RequestBody Userinfo userinfo){
System.out.println(userinfo);
List<Userinfo> userinfos = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Userinfo temp = new Userinfo();
temp.setUsername("miracle" + i);
temp.setPassword("123456" + i);
temp.setAge(i);
temp.setDate(new Date());
userinfos.add(temp);
}
return userinfos;
}
}
5.内部原理
- 通过使用 @RequestBody 注解将请求信息转化并绑定到处理方法的入参中
- 通过使用 @ResponseBody 注解将响应结果转为对应类型的响应信息
- 以上两个注解都是调用 HttpMessageConverter 完成内容转换
使用 @RequestBody 和 @ResponseBody 注解时,具体调用HttpMessageConverter的哪个实现,取决于转换类型,如上图
九.文件上传
1.概述
2.环境依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
3.springMVC配置文件
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="1024000"></property>
</bean>
4.jsp
<form action="/testFileUpload" method="post" enctype="multipart/form-data">
File:<input type="file" name="file">
Desc:<input type="text" name="desc">
<input type="submit" value="submit">
</form>
5.controller
@RequestMapping("/testFileUpload")
public String testFileUpload(@RequestParam("desc") String desc,
@RequestParam("file")MultipartFile file) throws IOException {
System.out.println(desc);
System.out.println(file.getOriginalFilename());
System.out.println(file.getInputStream());
return "success";
}
九.拦截器
1.概述
2.向springMVC配置文件注册拦截器
<mvc:interceptors>
<!--这里可以配置多个拦截器-->
<!--配置自定义的拦截器,默认拦截所有-->
<bean class="com.miracle.interceptors.FirstInterceptor"></bean>
<!--配置自定义的拦截器,拦截指定路径-->
<mvc:interceptor>
<mvc:mapping path="/url"/>
<bean class="bean"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:exclude-mapping path="/url"/>
<bean class="bean"></bean>
</mvc:interceptor>
</mvc:interceptors>
注意:多个拦截器的执行顺序
- (1)对于拦截器方法 preHandle :按照配置的顺序执行
- (2)对于拦截器方法 postHandle :按照配置的反序执行
- (3)对于拦截器方法 afterCompletion :按照配置的反序执行
3.编写拦截器
package com.miracle.interceptors;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FirstInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
}
十.异常处理
HandlerExceptionResolver是一个接口,下面介绍几个实现
1.ExceptionHandlerExceptionResolver
- 主要处理Handler中用 @ExceptionHandler 注解定义的方法
- 多个 @ExceptionHandler 注解定义的方法优先级问题:如果发生的是NullPointerException,但是声明的异常有RuntimeException 和 Exception,此时会根据异常的继承关系找,最近的,即标记了RuntimeException的方法
- 若controller中没有 @ExceptionHandler 注解修饰的方法,就会找 标记了 @ControllerAdvice 类 中 标记 @ExceptionHandler 注解修饰的方法
示例一,将异常处理方法定义在一个controller中,此时只能处理这个controller中的异常
package com.miracle.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class UserController {
// 这里接收class数组,为要捕获异常类的class数组
@ExceptionHandler({ArithmeticException.class}) // 注入 Exception 对象,获取异常信息
public ModelAndView handleArithmeticException(Exception ex){
System.out.println("出异常了:" + ex);
// 向前台展示数据只能使用,ModelAndView 对象
ModelAndView modelAndView = new ModelAndView("error");
modelAndView.addObject("ex", ex);
return modelAndView;
}
@RequestMapping("/testExceptionHandlerExceptionResolver")
public String testExceptionHandlerExceptionResolver(Integer i){
// 这里模拟异常
System.out.println("result: " + (10 / i));
return "success";
}
}
示例二,将异常处理方法统一定义在一个 @ControllerAdvice 注解修饰的类中,此时这些异常处理方法能处理IOC容器中所有controller的异常
package com.miracle.ExceptionHandler;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class HandleException {
// 这里接收class数组,为要捕获异常类的class数组
@ExceptionHandler({ArithmeticException.class}) // 注入 Exception 对象,获取异常信息
public ModelAndView handleArithmeticException(Exception ex){
System.out.println("-->出异常了:" + ex);
// 向前台展示数据只能使用,ModelAndView 对象
ModelAndView modelAndView = new ModelAndView("error");
modelAndView.addObject("ex", ex);
return modelAndView;
}
}
如果定义了全局处理异常方法 和 controller处理异常的方法,当这个controller出错时,优先找controller内部的方法处理
2.SimpleMappingExceptionResolver
在springMVC配置文件中
<!--配置使用 SimpleMappingExceptionResolver 来处理异常-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!--设置springMVC捕获异常后,将异常传到前台时,前台获取异常对象的 key 这里为 ex-->
<property name="exceptionAttribute" value="ex"></property>
<property name="exceptionMappings">
<!--定义异常映射集合-->
<props>
<!--出现Exception时,转向error页面-->
<prop key="java.lang.Exception">error</prop>
</props>
</property>
</bean>
十一.springMVC请求流程
十二.spring集成springMVC 父子容器关系
1.父子容器关系
- springMVC 的 IOC 容器中的bean可以引用spring IOC 容器中的bean,体现为:controller可以注入Service
- 反过来却不行