SpringMVC

Spring MVC

Spring MVC是什么?

Spring MVC是Spring框架中的一个分支,是目前最好的实现MVC设计模式的框架,以Spring框架的IoC容器为基础,并利用容器的特性来简化它的配置,Spring MVC相当于Spring的一个子模块,可以很好地和Spring框架进行整合开发,是Java Web开发者必须要掌握的框架。

Spring MVC能干什么?

实现了MVC设计模式,该设计模式是一种常用的软件架构方式:以Controller(控制层)、Model(模型层)、View(视图层)三个模块分离的形式来组织代码。

MVC流程:控制层接收到客户端请求,调用模型层生成业务数据,传递给视图层,将最终的业务数据和视图响应给客户端做展示。

Spring MVC就是对这套流程的封装,屏蔽了很多底层代码,开放出接口,让开发者可以更加轻松快捷地完成基于MVC设计模式的Web开发。

Spring MVC实现原理

Spring MVC环境搭建及其使用

Spring MVC常用的注解

映射Cookie

使用POJO绑定参数

重定向和转发

Spring MVC数据绑定

Spring MVC 视图解析

Spring MVC 自定义数据类型转换器

Spring MVC 集成RESTful架构

HiddenHttpMethodFilter

Spring MVC 文件的上传下载

Spring MVC 表单标签库


Spring MVC 实现原理

核⼼组件

在这里插入图片描述

  • (1)DispatcherServlet:前端控制器, 负责调度其他组件的执⾏,可降低不同组件之间的耦合性,Spring MVC 的核⼼模块。

  • (2)Handler:处理器, 完成具体的业务逻辑。(相当于Servlet)

  • (3)HandlerMapping: DispatcherServlet 是通过 HandlerMapping 将请求映射到不同的 Handler。

  • (4)HandlerInterceptor:处理器拦截器, 是⼀个接⼝,如果需要完成⼀些拦截处理,可以实现该接⼝

  • (5)HandlerExecutionChain:处理器执⾏链, 包括两部分内容,Handler 和 HandlerInterceptor。

  • (6)HandlerAdapter:处理器适配器, 它可以完成执⾏业务逻辑之前的⼀些预处理,数据类型转换、封装等, DispatcherServlet 通过 HandlerAdapter 调⽤不同的Handler。

  • (7)ModelAndView:装载了模型数据和视图信息, 作为 Hanlder 的处理结果,返回给DispatcherServlet。

  • (8)ViewResolver:视图解析器, DispatcherServlet 通过它将逻辑视图转换成物理视图,最终将渲染结果响应给客户端。

返回最顶层


工作流程

  • 1.客户端请求被 DispatcherServlet 接收。

  • 2.根据 HandlerMapping 映射到 Handler。

  • 3.创建 Handler 和 HandlerInterceptor。

  • 4.Handler 和 HandlerInterceptor 以 HandlerExecutionChain 的形式⼀并返回给DispatcherServlet。

  • 5.DispatcherServlet 通过 HandlerAdapter 调⽤ Handler 的⽅法完成业务逻辑处理。

  • 6.返回⼀个 ModelAndView 对象给 DispatcherServlet。

  • 7.DispatcherServlet 将获取的 ModelAndView 对象传给 ViewResolver ,将逻辑视图解析为物理视图View。

  • 8.ViewResolver 返回⼀个 View 给 DispatcherServlet。

  • 9.DispatcherServlet 根据 View 进⾏视图渲染(将模型数据填充到视图中)。

  • 10.DispatcherServlet 将渲染后的视图响应给客户端。

在这里插入图片描述

返回最顶层


Spring MVC的使用

pom.xml
web.xml
springmvc.xml

返回最顶层


pom.xml

<dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.1.9.RELEASE</version>
    </dependency>
</dependencies>

返回本节头部


在 web.xml 中配置 Spring MVC 的 DispatcherServlet。

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

返回本节头部


springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">

    <!-- 配置⾃动扫描 -->
    <context:component-scan base-package="com.chenny"></context:component-scan>
    <!-- 配置视图解析器 -->
    <bean
            class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

返回本节头部


Spring MVC常用的注解

  • @RequestMapping

    Spring MVC 通过 @RequestMapping 注解将请求与业务⽅法进⾏映射,在⽅法定义处,在类定义都可以添加该注解。


    Spring MVC通过@RequestMapping注解将url请求与业务方法进行映射,在控制器的类定义处以及方法定义处都可添加@RequestMapping注解,在类定义处添加@RequestMapping注解,相当于多了一层访问路径。

  • @RequestMapping 常⽤参数

  1. value:指定请求的实际地址, @RequestMapping 的默认值。
  2. method:指定请求的类型, GET、 POST、 PUT、 DELETE。
  3. params:指定请求必须包含的参数。
package com.chenny.controller;

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;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/hello")
public class HelloHandler {
    //value浏览器传入的值
    @RequestMapping(value = "/index",method = RequestMethod.GET,params = {"id=10","name"})  
    public String index(@RequestParam("id") int num,@RequestParam("name") String name){
        System.out.println(num);
        System.out.println(name);
        return "show";
        //return 是返回的jsp页面的名字
    }

    @RequestMapping("/rest/{id}/{name}")
    public String rest(@PathVariable("id") int num,@PathVariable("name") String name){
        System.out.println(num);
        System.out.println(name);
        return "show";
    }
}

  • 参数绑定
  1. 在业务⽅法定义时声明参数列表。

  2. 给参数添加 @RequestParam 注解。

  3. SpringMVC 也⽀持 RESTful ⻛格的 URL 参数获取

    @RequestMapping(value = "/index",params = {"name","value"})
        public String index(@RequestParam("name") String name,@RequestParam("value") String value){
            System.out.println(name);
            System.out.println(value);
            return "show";
        }
    
    传统: http://localhost:8080/hello/index?id=10&name=1
    RESTful: http://localhost:8080/hello/rest/10/1
    
	/*
	*  传统风格
	*/
	@RequestMapping(value = "/index",method = RequestMethod.GET,params = {"id=10","name"})
	public String index(@RequestParam("id") int num,@RequestParam("name") String gender){
	    System.out.println(num);
	    System.out.println(gender);
	    return "index";
	}
	/*
    * Restful风格
    */
	@RequestMapping("/rest/{id}/{name}")
    public String rest(@PathVariable("id") int id ,@PathVariable("name") String name){

        return "show";
    }

返回头部


映射Cookie

@RequestMapping("/cookie")
public String cookie(@CookieValue("JSESSIONID") String sessionId){
	System.out.println(sessionId);
	return "index";
}

返回头部


重定向和转发

Spring MVC默认以转发的形式响应JSP,也可以自主进行设置

重定向:

@RequestMapping("/cookie")
public String getCookie(@CookieValue("JSESSIONID") String sessionId){
    System.out.println(sessionId);
    return "redirect:/index.jsp";
}

转发:

@RequestMapping("/cookie")
public String getCookie(@CookieValue("JSESSIONID") String sessionId){
    System.out.println(sessionId);
    return "forward:/index.jsp";
}

返回头部


Spring MVC 数据绑定

什么是数据绑定?在后台业务方法中,直接获取前端HTTP请求中参数的形式,将HTTP请求中的参数之间绑定到业务方法参数列表的方式就是数据绑定。

  • 底层原理:HTTP请求传输的参数都是String类型,但是Handler的业务方法中的参数都是开发者指定的数据类型,如int、Object等,所以需要处理参数的类型转换。具体的转换工作不需要开发者去完成,Spring MVC的HandlerAdapter组件会在执行Handler业务方法之前,完成参数的绑定。

基本数据类型
  • 以int为例,后台需要int类型的参数,直接在业务方法定义处添加int类型的形参即可,HTTP请求参数名称要与形参保持一致。

  • @ResponseBody 注解直接将数据以字符串的形式响应给客户端。

@RequestMapping("/baseType")
@ResponseBody
public String baseType(@RequestParam("id") int num){
    System.out.println(num+1);
    return "num:"+num;
}
包装类
@RequestMapping("/packageType")
@ResponseBody
public String packageType(@RequestParam(value = "num",required = false,defaultValue = "1") Integer num){
    return "num:"+num;
}
  • @RequestParam:
    • value = “num”: 将HTTP请求中名为num的参数与形参进行映射。
    • required = false: num参数为非必填项,可以省略。
    • defaultValue = “1”: 若HTTP请求中没有num参数,默认值为1。

返回头部


数组
@RequestMapping("/arrayType")
@ResponseBody
public String arrayType(String[] name){
    StringBuffer stringBuffer = new StringBuffer();
    for(String item:name){
        stringBuffer.append(item).append(" ");
    }
    return "name:"+stringBuffer.toString();
}

返回头部


List

List的自定义包装类:

public class UserList {
    private List<User> users;

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }
}
@RequestMapping("/listType")
@ResponseBody
public String listType(UserList userList){
    StringBuffer stringBuffer = new StringBuffer();
    for(User user:userList.getUsers()){
        stringBuffer.append(user).append(" ");
    }
    return "用户:"+stringBuffer.toString();
}

创建addList.jsp,同时添加3个用户信息,input的name指向自定义包装类UserList的users属性,及联到name和age,同时以下标区分集合中不同的对象。

<form action="/data/listType" method="post">
    用户1ID:<input type="text" name="users[0].id"/><br/>
    用户1姓名:<input type="text" name="users[0].name"/><br/>
    用户2ID:<input type="text" name="users[1].id"/><br/>
    用户2姓名:<input type="text" name="users[1].name"/><br/>
    用户3ID:<input type="text" name="users[2].id"/><br/>
    用户3姓名:<input type="text" name="users[2].name"/>
    <input type="submit" value="提交"/>
</form>

@ResponseBody出现中文乱码的解决方法,在springmvc.xml中配置消息转换器。

<mvc:annotation-driven>
    <!-- 消息转换 -->
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

返回头部


Map

List的自定义包装类:

public class UserMap {
    private Map<String,User> users;

    public Map<String, User> getUsers() {
        return users;
    }

    public void setUsers(Map<String, User> users) {
        this.users = users;
    }
}
业务方法:
@RequestMapping("/mapType")
@ResponseBody
public String mapType(UserMap userMap){
    StringBuffer stringBuffer = new StringBuffer();
    for (String key:userMap.getUsers().keySet()){
        User user = userMap.getUsers().get(key);
        stringBuffer.append(user).append(" ");
    }
    return "用户:"+stringBuffer.toString();
}
addMap.jsp
<form action="/data/mapType" method="post">
    用户1ID:<input type="text" name="users['a'].id"/><br/>
    用户1姓名:<input type="text" name="users['a'].name"/><br/>
    用户2ID:<input type="text" name="users['b'].id"/><br/>
    用户2姓名:<input type="text" name="users['b'].name"/><br/>
    用户3ID:<input type="text" name="users['c'].id"/><br/>
    用户3姓名:<input type="text" name="users['c'].name"/><br/>
    <input type="submit" value="提交"/>
</form>

返回头部


Set

需要封装自定义包装类,将Set集合作为属性,不同的是,使用Set集合,需要在包装类构造函数中,为Set集合添加初始化对象。

public class UserSet {
    private Set<User> userSet = new HashSet<>();

    public UserSet(){
        userSet.add(new User());
        userSet.add(new User());
        userSet.add(new User());
    }
}
业务方法:
@RequestMapping("/setType")
@ResponseBody
public String setType(UserSet userSet){
    StringBuffer stringBuffer = new StringBuffer();
    for (User user:userSet.getUserSet()){
        stringBuffer.append(user).append(" ");
    }
    return "用户:"+stringBuffer.toString();
}
addSet.jsp
<form action="/data/setType" method="post">
    用户1ID:<input type="text" name="users[0].id"/><br/>
    用户1姓名:<input type="text" name="users[0].name"/><br/>
    用户2ID:<input type="text" name="users[1].id"/><br/>
    用户2姓名:<input type="text" name="users[1].name"/><br/>
    用户3ID:<input type="text" name="users[2].id"/><br/>
    用户3姓名:<input type="text" name="users[2].name"/><br/>
    <input type="submit" value="提交"/>
</form>

JSON

JSP:Ajax请求后台业务方法,并将json格式的参数传给后台。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script src="js/jQuery-1.8.3.js"></script>
    <script type="text/javascript">
        $(function () {
            var user = {
                "id":1,
                "name": "张阿三",
            };
            $.ajax({
               url:"data/json",
                data:JSON.stringify(user),
                type:"POST",
                contentType:"application/json;charset=UTF-8",
                dataType:"text",
                success:function (data){
                   alert(data)
                }
            });
        })
    </script>
</head>
<body>

</body>
</html>

Spring MVC会拦截静态资源的请求,需要在web.xml中进行配置。

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
</servlet-mapping>

业务方法:

	@RequestMapping("/json")
    @ResponseBody
    public String json(@RequestBody User user){
        System.out.println(user);
        return user.toString();
    }

@RequestBody:读取HTTP请求参数,通过Spring MVC提供的HttpMessageConverter接口将读取的参数转为json,xml格式的数据,绑定到业务方法的形参中。

@ResponseBody:将业务方法返回的对象,通过HttpMessageConverter接口转为指定格式的数据,json、xml等,响应给客户端。

fastjson来完成转换工作,fastjson的优势在于如果属性为空就不会将其转化为json,数据会简洁很多。

如何使用fastjson

  • pom.xml中引入fastjson的依赖。
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.18</version>
</dependency>
  • springmvc.xml中配置fastjson。
<mvc:annotation-driven>
    <!-- 消息转换 -->
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
        </bean>
        <!-- fastjson -->
        <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4"></bean>
    </mvc:message-converters>
</mvc:annotation-driven>

返回最顶层


SpringMVC 视图解析

业务数据的绑定是指将业务数据绑定给 JSP 域对象,并且在客户端进行展示。pageContext、request、session、application


业务数据的绑定是由 ViewResolver 完成。


Spring MVC 提供了以下几种方式绑定业务数据:

  • Map
  • Model
  • ModelAndView
  • @SessionAttribute
  • @ModelAttribute

返回最顶层


业务数据绑定到Request域对象
Map
  • Spring MVC 在内部使⽤ Model 接⼝存储业务数据,在调⽤业务⽅法之前会创建⼀个隐含对象作为业务数据的存储容器。
  • 设置业务⽅法的⼊参为 Map 类型,Spring MVC 会将隐含对象的引⽤传递给⼊参。
  • 开发者可以对模型中的所有数据进⾏管理,包括访问和添加、修改、删除。
  • 开发者只需要在业务⽅法处添加 Map 类型的⼊参,⽅法体中便可以通过对⼊参的操作来完成业务数据的添加。
@Controller
@RequestMapping("/view")
public class ViewHandler {

    @RequestMapping("/map")
    public String mapTest(Map<String, User> userMap){
        User user = new User(1,"张三","23",new Address(1,"科技类"));
        userMap.put("user",user);
        return "show";
    }
}
Model

与 Map 类似,业务方法通过入参来完成业务数据的绑定。

@RequestMapping("/model")
    public String modelTest(Model model){
        User user = new User(1,"李四","23",new Address(1,"科技类"));
        model.addAttribute("user",user);
        return "show";
    }
Request
 @RequestMapping("/request")
    public String request(HttpServletRequest request){
        User user = new User(1,"王五","23",new Address(1,"科技类"));
        request.setAttribute("user",user);
        return "show";
    }

ModelAndView

Map、Model 不同的是,ModelAndView 不但包含了业务数据,同时也包含了视图信息,将视图和业务数据进行了整合,封装成一个对象,如果使用 ModelAndView 来处理业务数据,业务方法的返回值必须是 ModelAndView 对象。


业务方法中对 ModelAndView 进行两个操作:

  • 填充业务数据
  • 绑定视图信息
	@RequestMapping("modelAndView")
    public ModelAndView modelAndView(){
        User user = new User(1,"赵六","23",new Address(1,"科技类"));
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("user",user);
        modelAndView.setViewName("show");
        return modelAndView;
    }

    @RequestMapping("modelAndView2")
    public ModelAndView modelAndView2(){
        User user = new User(1,"赵六","23",new Address(1,"科技类"));
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("user",user);
        InternalResourceView view = new InternalResourceView("/show.jsp");
        modelAndView.setView(view);
        return modelAndView;
    }
    
	@RequestMapping("modelAndView3")
    public ModelAndView modelAndView3(){
        User user = new User(1,"威威","23",new Address(1,"科技类"));
        ModelAndView modelAndView = new ModelAndView("show");
        modelAndView.addObject("user",user);
        return modelAndView;
    }

    @RequestMapping("modelAndView4")
    public ModelAndView modelAndView4(){
        InternalResourceView view = new InternalResourceView("/show.jsp");
        ModelAndView modelAndView = new ModelAndView(view);
        User user = new User(1,"宝宝","23",new Address(1,"科技类"));
        modelAndView.addObject("user",user);
        return modelAndView;
    }

    @RequestMapping("modelAndView5")
    public ModelAndView modelAndView5(){
        User user = new User(1,"靓靓","23",new Address(1,"科技类"));
        Map<String,User> map = new HashMap<String,User>();
        map.put("user",user);
        ModelAndView modelAndView = new ModelAndView("show",map);
        return modelAndView;
    }

    @RequestMapping("modelAndView6")
    public ModelAndView modelAndView6(){
        User user = new User(1,"侃侃","23",new Address(1,"科技类"));
        Map<String,User> map = new HashMap<String,User>();
        map.put("user",user);
        InternalResourceView view = new InternalResourceView("/show.jsp");
        ModelAndView modelAndView = new ModelAndView(view,map);
        return modelAndView;
    }

    @RequestMapping("modelAndView7")
    public ModelAndView modelAndView7(){
        User user = new User(1,"阿萨","23",new Address(1,"科技类"));
        ModelAndView modelAndView = new ModelAndView("show","user",user);
        return modelAndView;
    }

ModelAttribute

  • 定义一个方法,该方法用来返回要填充到业务数据中的对象。
  • 给该方法添加 @ModelAttribute 注解,该方法不是业务方法。
@RequestMapping("/modelAttribute")
    public String modelAttribute(){

        return "show";
    }



//    @ModelAttribute
//    public User getUser(){
//        User user = new User(1,"娥娥","23",new Address(1,"科技类"));
//        return user;
//    }

//    @ModelAttribute
//    public void getUser(Model model){
//        User user = new User(1,"憨憨","23",new Address(1,"科技类"));
//        model.addAttribute(user);
//    }

    @ModelAttribute
    public void getUser(Map<String,User> map){
        User user = new User(1,"淡淡","23",new Address(1,"科技类"));
        map.put("user",user);
    }
业务数据绑定到Session域对象
	@RequestMapping("/session")
    public String session(HttpServletRequest request){
        User user = new User(1,"小明","23",new Address(1,"科技类"));
        request.getSession().setAttribute("user",user);
        return "test";
    }

    @RequestMapping("/session2")
    public String session2(HttpSession httpSession) {
        User user = new User(1, "校长", "23", new Address(1, "科技类"));
        httpSession.setAttribute("user", user);
        return "test";
    }
sessionAttribute

在类定义处添加 @SessionAttributes 注解,只要业务方法中向域对象中存入了模型数据,则 Spring MVC 会自动把它同步到 session 中。

@Controller
@RequestMapping("/view")
@SessionAttributes(value = "user")
public class ViewHandler {

    @RequestMapping("/mavtest")
    public ModelAndView mavtest(){
        User user = new User(1, "依依", "23", new Address(1, "科技类"));
        ModelAndView modelAndView = new ModelAndView("test");
        modelAndView.addObject(user);
        return modelAndView;
    }
}

返回最顶层


Spring MVC 自定义数据类型转换器

spring MVC
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="com.chenny.convert.DateConverter">
                    <constructor-arg type="java.lang.String" value="yyyy-MM-dd"></constructor-arg>
                </bean>

                <bean class="com.chenny.convert.StudentConvert"></bean>
            </list>
        </property>
    </bean>

    <mvc:annotation-driven conversion-service="conversionService"/>
StudentConvert
package com.chenny.convert;

import com.chenny.entity.Student;
import org.springframework.core.convert.converter.Converter;

public class StudentConvert implements Converter<String, Student> {
    @Override
    public Student convert(String s) {
        String[] args = s.split("-");
        Student student = new Student();
        student.setId(Integer.parseInt(args[0]));
        student.setName(args[1]);
        student.setAge(args[2]);
        return student;
    }
}
ConvertHandler
package com.chenny.controller;


import com.chenny.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;

@Controller
@RequestMapping("/convert")
public class ConvertHandler {

    @RequestMapping("/test")
    public String test(Date date){
        System.out.println(date);
        return "index";
    }


    @RequestMapping("/student")
    @ResponseBody
    public String student(Student student){
        return student.toString();
    }
}

返回最顶层


Spring MVC 集成RESTful架构

REST:Representational State Transfer 资源表现层状态转换

  • Resources:资源

  • Representation:资源表现层

  • State Transfer:状态转换

RESTful 有以下两个特点:

  • URL 传参更加简洁

    传统的 URL:http://localhost/8080/test?id=1

    RESTful:http://localhost/8080/test/1

  • 完成不同终端之间的资源共享,RESTful 提供了一套规范,不同终端之间只需要遵守该规范,就可以实现数据交互。

RESTful 具体来讲就是 4 种表现形式,HTTP 协议中的四种请求类型(GET、POST、PUT、DELETE)分别对应四种常规操作,CRUD。

  • GET 用来获取资源
  • POST 用来创建资源
  • PUT 用来修改资源
  • DELETE 删除资源

返回最顶层


Spring MVC模型数据解析

Spring MVC提供了以下几种方法添加模型数据:

  • Map
  • Model
  • ModelAndView
  • @SessionAttributes
  • @ModelAttribute
模型数据绑定到request对象中
  • Map,开发者只需要在业务方法中定义Map形参,方法体中对该形参进行操作,Spring MVC框架会自动取出该形参中的数据并存入request对象,可以在JSP通过EL表达式直接获取对象。
@RequestMapping("/map")
public String map(Map<String, Course> map){
    Course course = new Course(1,"Java基础",2000);
    map.put("c1",course);
    return "test";
}
  • Model,Model的使用与Map类似。
@RequestMapping("/model")
public String model(Model model) {
    Course course = new Course(1,"Java基础",2000);
    model.addAttribute("c1",course);
    return "test";
}
  • ModelAndView

与Map、Model不同的是,ModelAndView不但包含模型数据,同时也包含了视图信息,所以使用ModelAndView来处理模型数据,业务方法的返回值必须是ModelAndView,业务方法中对ModelAndView进行两个操作:1、填充模型数据。2、绑定视图信息。

@RequestMapping("/mav1")
public ModelAndView modelAndView1(){
    ModelAndView modelAndView = new ModelAndView();
    Course course = new Course(1,"Java基础",2000);
    modelAndView.addObject("c1",course);
    modelAndView.setViewName("test");
    return modelAndView;
}

@RequestMapping("/mav2")
public ModelAndView modelAndView2(){
    ModelAndView modelAndView = new ModelAndView();
    Course course = new Course(1,"Java基础",2000);
    modelAndView.addObject("c1",course);
    View view = new InternalResourceView("/test.jsp");
    modelAndView.setView(view);
    return modelAndView;
}

@RequestMapping("/mav3")
public ModelAndView modelAndView3(){
    ModelAndView modelAndView = new ModelAndView("test");
    Course course = new Course(1,"Java高级",2000);
    modelAndView.addObject("c1",course);
    return modelAndView;
}

@RequestMapping("/mav4")
public ModelAndView modelAndView4(){
    View view = new InternalResourceView("/test.jsp");
    ModelAndView modelAndView = new ModelAndView(view);
    Course course = new Course(1,"Java高级",2000);
    modelAndView.addObject("c1",course);
    return modelAndView;
}

@RequestMapping("/mav5")
public ModelAndView modelAndView5(){
    Map<String,Course> map = new HashMap<>();
    Course course = new Course(3,"Spring MVC框架",3000);
    map.put("c1",course);
    ModelAndView modelAndView = new ModelAndView("test",map);
    return modelAndView;
}

@RequestMapping("/mav6")
public ModelAndView modelAndView6(){
    Map<String,Course> map = new HashMap<>();
    Course course = new Course(3,"Spring MVC框架",3000);
    map.put("c1",course);
    View view = new InternalResourceView("/test.jsp");
    ModelAndView modelAndView = new ModelAndView(view,map);
    return modelAndView;
}

@RequestMapping("/mav7")
public ModelAndView modelAndView7(){
    Course course = new Course(1,"Java基础",2000);
    ModelAndView modelAndView = new ModelAndView("test","c1",course);
    return modelAndView;
}

@RequestMapping("/mav8")
public ModelAndView modelAndView8(){
    Course course = new Course(2,"Spring框架",3000);
    View view = new InternalResourceView("/test.jsp");
    ModelAndView modelAndView = new ModelAndView(view,"c1",course);
    return modelAndView;
}
  • HttpServletRequest、HttpSession
@RequestMapping("/request")
public String request(HttpServletRequest request){
    Course course = new Course(1,"Java基础",2000);
    request.setAttribute("c1",course);
    HttpSession session = request.getSession();
    session.setAttribute("c1",course);
    return "test";
}

@RequestMapping("/session")
public String session(HttpSession session){
    System.out.println(session);
    session.setAttribute("c1",new Course(1,"Java",2000));
    return "test";
}

HiddenHttpMethodFilter

实现原理:检测请求参数中是否包含 _method 参数,如果包含则获取该参数的值,判断是哪种操作后完成请求类型的转换,然后继续传递。

1、在 form 表单中添加隐藏域标签,name="_method",value=“PUT”/“DELETE”。

<form action="/rest/put" method="post">
  <input type="hidden" name="_method" value="PUT"/>
  <input type="submit"/>
</form>
<form action="/rest/delete" method="post">
  <input type="hidden" name="_method" value="DELETE"/>
  <input type="submit"/>
</form>

2、web.xml 配置 HiddenHttpMethodFilter

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

3、RestHandler

package com.southwind.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/rest")
public class RestHandler {

    @RequestMapping(value = "/put",method = RequestMethod.PUT)
    @ResponseBody
    public String rest(){
        System.out.println("rest");
        return "PUT";
    }

    @RequestMapping(value = "/delete",method = RequestMethod.DELETE)
    @ResponseBody
    public String delete(){
        System.out.println("delete");
        return "DELETE";
    }
}

返回最顶层

需求

  • 添加课程,成功则返回全部课程信息。
  • 查询课程,通过 id 查询对应的课程信息。
  • 修改课程,成功则返回修改之后的全部课程信息。
  • 删除课程,成功则返回删除之后的全部课程信息。

1、创建实体类

package com.southwind.entity;

public class Course {
    private Integer id;
    private String name;
    private Double price;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Course(Integer id, String name, Double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }
}

2、CourseRepository

package com.southwind.repository;

import com.southwind.entity.Course;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@Repository
public class CourseRepository {
    private static Map<Integer, Course> map;

    static {
        map = new HashMap();
        map.put(1,new Course(1,"Java",6000d));
        map.put(2,new Course(2,"C++",6000d));
        map.put(3,new Course(3,"Python",6000d));
    }

    public void saveOrUpdate(Course course){
        map.put(course.getId(),course);
    }

    public Collection<Course> findAll(){
        return map.values();
    }

    public Course findById(Integer id){
        return map.get(id);
    }

    public void deleteById(Integer id){
        map.remove(id);
    }
}

3、CourseHandler

package com.southwind.controller;

import com.southwind.entity.Course;
import com.southwind.repository.CourseRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/course")
public class CourseHandler {
    @Autowired
    private CourseRepository courseRepository;

//    @RequestMapping(value = "/findAll",method = RequestMethod.GET)
    @GetMapping("/findAll")
    public ModelAndView findAll(){
        ModelAndView modelAndView = new ModelAndView("course");
        modelAndView.addObject("list",courseRepository.findAll());
        return modelAndView;
    }

    @DeleteMapping("/deleteById/{id}")
    public String deleteById(@PathVariable("id") Integer id){
        courseRepository.deleteById(id);
        return "redirect:/course/findAll";
    }

    @GetMapping("/findById/{id}")
    public ModelAndView findById(@PathVariable("id") Integer id){
        ModelAndView modelAndView = new ModelAndView("update");
        modelAndView.addObject("course",courseRepository.findById(id));
        return modelAndView;
    }

    @PutMapping("/update")
    public String update(Course course){
        courseRepository.saveOrUpdate(course);
        return "redirect:/course/findAll";
    }

    @PostMapping("/add")
    public String add(Course course){
        courseRepository.saveOrUpdate(course);
        return "redirect:/course/findAll";
    }
}

返回最顶层


Spring MVC 的文件上传下载

  • 单文件上传
pom.xml
	<dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.7</version>
    </dependency>

    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.4</version>
	</dependency>
JSP
  • input 的 type 设置为 file
  • form 表单的 method 设置为 post
  • form 表单的 enctype 设置为 multipart/form-data
<%--
  Created by IntelliJ IDEA.
  User: 73981
  Date: 2020/9/13
  Time: 13:39
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/unload" method="post" enctype="multipart/form-data">
        <input type="file" name="img"/>
        <input type="submit" value="上传"/>
    </form>
    <br>
    <c:if test="${filepath !=null}">
        <h1>上传的图片</h1>
        <img width="300px" src="${filepath}" alt="">
    </c:if>
</body>
</html>

返回最顶层


Spring MVC 表单标签库

1、在 JSP 页面中导入 Spring MVC 标签库,与导入 JSTL 标签库的语法非常相似,前缀 prefix 可以自定义,通常为 from。

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

2、将 form 表单与业务数据进行绑定,通过 modelAttribute 属性完成绑定,将 modelAttribute 的值设置为控制器向 ModelAndView 对象存值时的 key 即可。

package com.chenny.controller;

import com.chenny.entity.Person;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/person")
public class PersonHandler {

    @GetMapping("/get")
    public ModelAndView get(){
        ModelAndView modelAndView = new ModelAndView();
        Person person = new Person();
        person.setId(1);
        person.setName("张三");
        person.setAge(22);
        person.setGender("男");
        modelAndView.addObject("person",person);
        modelAndView.setViewName("person");
        return modelAndView;
    }
}
<form:form modelAttribute="person">
  用户编号:<form:input path="id"></form:input>
  用户姓名:<form:input path="name"></form:input>
  用户年龄:<form:input path="age"></form:input>
  用户性别:<form:input path="gender"></form:input>
</form:form>

3、form 表单与业务数据完成绑定后,接下来就是将业务数据中的值取出绑定到不同的标签中,通过设置标签的 path 属性完成,将 path 属性的值设置为业务数据对应的属性名即可。

  • from 标签
<form:form modelAttribute="person" method="post"></form:form>

渲染的是 HTML 中的 ,通过 modelAttribute 属性绑定具体的业务数据。

  • input 标签
<form:input path="name"/>

渲染的是 HTML 中的 ,form 标签绑定的是业务数据,input 标签绑定的是业务数据中的属性值,通过 path 与业务数据的属性名对应,并支持级联属性。

  • password 标签
<form:password path="password"/>

渲染的是 HTML 中的 ,通过 path 属性与业务数据的属性名对应,password 标签的值不会在页面显示。

  • checkbox 标签
<form:checkbox path="hobby" value="读书"/>读书

渲染的是 HTML 中的 ,通过 path 与业务数据的属性名对应,可以绑定 boolean、数组和集合。

如果绑定 boolean 类型的变量,该变量的值为 true,则表示选中,false 表示不选中。

如果绑定数组或者集合类型,数组/集合中的元素等于 checkbox 的 value 值,则该项选中,否则不选中。

用户爱好:<form:checkbox path="hobby" value="读书"></form:checkbox>读书
<form:checkbox path="hobby" value="看电影"></form:checkbox>看电影
<form:checkbox path="hobby" value="打游戏"></form:checkbox>打游戏
<form:checkbox path="hobby" value="听音乐"></form:checkbox>听音乐
<form:checkbox path="hobby" value="旅行"></form:checkbox>旅行
<hr/>
用户爱好:<form:checkbox path="hobby2" value="读书"></form:checkbox>读书
<form:checkbox path="hobby2" value="看电影"></form:checkbox>看电影
<form:checkbox path="hobby2" value="打游戏"></form:checkbox>打游戏
<form:checkbox path="hobby2" value="听音乐"></form:checkbox>听音乐
<form:checkbox path="hobby2" value="旅行"></form:checkbox>旅行
  • checkboxes 标签
<form:checkboxes items="${person.hobby}" path="selectHobby" />

渲染的是 HTML 中的一组 ,这里需要结合 items 和 path 两个属性来使用,items 绑定被遍历的集合或数组,path 绑定被选中的集合或数组,可以这样理解,items 为全部选型,path 为默认选中的选型。

用户爱好:<form:checkboxes path="selectHobbys" items="${person.hobbys}"></form:checkboxes>
<hr/>
用户爱好:<form:checkboxes path="selectHobbys2" items="${person.hobbys2}"></form:checkboxes>
  • radiobutton 标签
<form:radiobutton path="radioId" value="0"/>

渲染的是 HTML 只的一个 ,绑定的数据与标签的 value 值相等为选中状态,否则为不选中状态。

radio:<form:radiobutton path="radioId" value="0"></form:radiobutton>0
<form:radiobutton path="radioId" value="1"></form:radiobutton>1
  • radiobuttons 标签
<form:radiobuttons items="${person.grade}" path="selectGrade">

渲染的是 HTML 中的一组 ,这里需要结合 items 和 path 两个属性来使用,items 绑定被遍历的集合或数组,path 绑定被选中的值,可以这样理解,items 为全部选型,path 为默认选中的选型,用法与 form:checkboxes 一致。

  • select 标签
<form:select items="${person.citys}" path="selectCity">

渲染的是 HTML 中的一个 ,这里需要结合 items 和 path 两个属性来使用,items 绑定被遍历的集合或数组,path 绑定被选中的值,用法与 form:radiobuttons/ 一致。

  • options 标签

form:select 结合 form:options 使用,form:select 只定义 path 属性,在 form:select 标签内部添加一个子标签 form:options,设置 items 属性,获取被遍历的集合。

  • option 标签

from:select 结合 form:option 使用,form:select 定义 path 属性,给每一个 form:options 设置 values 属性,path 与哪个 value 相等,该项默认选中。

  • textarea 标签

渲染的是 HTML 中的一个 ,path 绑定业务数据的属性值,作为文本输入域的默认值。

  • errors 标签

该标签的使用需要结合 Spring MVC 的 Validator 验证器来使用,将验证结果的 error 信息渲染到 JSP 页面中。

1、创建验证器,实现 Validator 接口。

package com.chenny.validator;

import com.chenny.entity.Student;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

public class StudentValidator implements Validator {
    @Override
    public boolean supports(Class<?> aClass) {
        return Student.class.equals(aClass);
    }

    @Override
    public void validate(Object o, Errors errors) {
        ValidationUtils.rejectIfEmpty(errors,"name",null,"姓名不能为空");
        ValidationUtils.rejectIfEmpty(errors,"age",null,"年龄不能为空");
    }
}

2、springmvc.xml 中添加 Validator 配置。

<bean id="studentValidator" class="com.chenny.validator.StudentValidator"></bean>

<mvc:annotation-driven validator="studentValidator"></mvc:annotation-driven>

3、创建业务方法,第一个 login 方法用来生成业务数据,跳转到 login.jsp,第二个 login 方法用来做验证。

@GetMapping("/login")
public ModelAndView login(){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("student",new Student());
    modelAndView.setViewName("login");
    return modelAndView;
}

@PostMapping("/login")
public String reg(@Validated Student student, BindingResult bindingResult){
    if(bindingResult.hasErrors()){
        return "login";
    }
    return "index";
}

4、JSP

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form:form action="/person/login" method="post" modelAttribute="student">
        <form:input path="name"></form:input><form:errors path="name" /><br/>
        <form:input path="age"></form:input><form:errors path="age"/><br/>
        <input type="submit"/>
    </form:form>
</body>
</html>

返回最顶层




返回根目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值