springMVC基于注解开发

一.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
  • 反过来却不行
    在这里插入图片描述
2.两个IOC容器,在扫描bean时,是否会导致bean被创建两次

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值