SpringMvc教程

SpringMvc教程

1.基础

1.mvc的流程图

将应用程序分为Controller、Model、View三层。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z85RYLQY-1618990797969)(C:\Users\31797\Desktop\1.png)]

2.spring MVC的核心组件

  • DispatcherServlet:前置控制器,是整个流程控制的核心,控制其他组件,降低耦合性。

  • Hander:处理器,完成具体业务逻辑,相当于Servlet或Action

  • HandlerMapping:DispatchServlet接受请求之后,通过HandlerMapping将不同不同的请求映射到不同的Hander

  • HnaderInterceptor:处理器拦截口,是一个接口,完成一些拦截操作。

  • HandlerExecutionChain:处理器执行链,包括两部分:Handler和 HanderInterceptor

  • HanderAdaper:处理器适配器,Handler执行任前,需要一系列操作,包括数据转换,表单验证,将表单数据封装到JavaBean等。这些HanderAdapter都可以完成。DispatcherServlet通过HandlerAdapter执行不同的Handler。

  • ModelAndView:装载了模型数据和视图信息,作为Handler的处理结果,返回给DispacherServlet。

  • ViewResolver:视图解析器,DispatcheServlet通过它将逻辑视图变为物理视图,最终将渲染结果传给客户端。

3.spring mvc工作流程

1618749677033
  • 客户端请求被DispatcherServlet接受
  • 通过HandlerManpping映射到Handler
  • 生成Handler和HandlerInterceptor
  • Handler和HandlerInterceptor以HandlerExecutionChain的形式一并返回给DispatcherServlet.
  • DispatcherServlet通过HanderAdapter调用Handler的方法完成业务逻辑处理
  • Handler返回一个ModerAndView给DispatcherServlet。
  • DispatchServlet将获取的ModelAndView对象传给ViewResovler视图解析器,讲逻辑视图转为物理视图View。
  • ViewResovler返回一个View给DispatcherServlet。
  • DispatcherServlet根据View进行视图渲染(将模型数据Model填充到视图View中)。
  • DispatcherServlet将渲染的结果相应给客户端

4.spring mvc的特点

Spring MVC流程非常复杂,实际开发中很简单。真正处理的只有Handler、View.

5.如何使用

  • 创建Maven工程,pom.xml

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r1Bbfjr6-1618990797978)(C:\Users\31797\AppData\Roaming\Typora\typora-user-images\1618751669300.png)]

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

    第一次要加载才能正常显示

  • 在web.xml中配置DispacherServlet。

    要在resources下创建springmvc.xml文件

    <!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>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
    <!--      让spring读取springmvc的配置文件-->
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:springmvc.xml</param-value>
        </init-param>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
    <!--    拦截所有请求-->
        <url-pattern>/</url-pattern>
      </servlet-mapping>
    </web-app>
    
  • spring.xml进行配置

    <?xml version='1.0' encoding='UTF-8' ?>
    <!-- was: <?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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
    <!--        自动扫描,交给aoc管理-->
            <context:component-scan base-package="com.xxx"></context:component-scan>
    <!--    视图解析器-->
    <!--    把逻辑视图转化为物理视图-->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!--        前缀是根目录,表示webapp的根目录-->
            <property name="prefix" value="/"></property>
    <!--        表示后缀-->
            <property name="suffix" value=".jsp"></property>
        </bean>
    </beans>
    
  • 创建Handler(控制器)

    package com.xxx.controller;
    
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    //交给aoc容器管理
    //@Component,没有控制器的功能
    @Controller
    //区别不同的Handler
    @RequestMapping("/user")
    public class HelloHandler {
        @RequestMapping("/index")
        public String  index(){
            System.out.println("wwwwwwww");
            //逻辑视图
            return "index";
        }
    }
    

2.Spring Mvc注解

1.@RequestMapping

Spring Mvc通过@RequestMapping注解将URL请求和业务方法映射,在Handler的类定义及方法定义处都可以添加@RequstMapping,在类定义处添加,相当于客户端多了一从访问路径。

2.@Controller

@Controller在类的定义处添加,将该类交给IoC容器管理(结合springmvc.xml的自动扫描配置使用),同时使其成为一个控制器,可以接受客户端请求。

package com.xxx.controller;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

//交给aoc容器管理
//@Component,没有控制器的功能
@Controller
//区别不同的Handler
@RequestMapping("/user")
public class HelloHandler {
    @RequestMapping("/index")
    public String  index(){
        System.out.println("wwwwwwww");
        //逻辑视图
        return "index";
    }
}

3.@RequestMapping相关参数

1.value:指定URl的实际地址,是RequestMapping的默认值。
@RequestMapping("/index")
    public String  index(){
    System.out.println("wwwwwwww");
    //逻辑视图
    return "index";
}

等于

@RequestMapping(value="/index")
    public String  index(){
    System.out.println("wwwwwwww");
    //逻辑视图
    return "index";
}
2.method:指定请求的method类型:get、post、put、delete
@RequestMapping(value = "/index",method = RequestMethod.GET)
    public String  index(){
    System.out.println("wwwwwwww");
    //逻辑视图
    return "index";
}

上述代码表示index方法只能接受get请求

405错误:方法不被允许

不加就没有限制

3.params:指定参数中必须包含某些参数,否则无法调用该方法。
@RequestMapping(value = "/index",method = RequestMethod.GET,params{"name","id=10"})
    public String  index(){
        System.out.println("wwwwwwww");
        //逻辑视图
        return "index";
}

以上代码表示请求参数必须包含name和id两个参数,同时id的值必须是10。

在形参列表中通过添加**@RequsetParam**注解完成HTTP请求参数与业务方法的映射。

@RequestMapping(value = "/index",method = RequestMethod.GET,params {"name","id=12"})
    public String  index(@RequestParam("name") String ww,int id){
        System.out.println(ww+":"+id);
        System.out.println("wwwwwwww");
        //逻辑视图
        return "index";
}

上述代码表示将请求代码的参数name和id分别赋给了ww和id,并且自动完成了数据类型的转换,将“10”转化为int的10,再赋给id,这些工作都是由HandlerAdapter完成的。

4.Spring MVC也支持RESTful风格的URL。

传统风格:http://localhost:8080/user/index?name=zhangsan&id=10

RESTful:http://localhost:8080/user/index/zhangsan/10

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

通过@PathVarible注解完成请求参数与形参的映射,在RESTful风格中,这个注解必须存在,否则就无法完成映射,这一点与传统风格不同。

5.映射Cookie

Spring MVC通过映射可以直接在业务方法中获取Cookie的值。

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

上述代码,必须通过@CookieValue(value=“JESSIONID”)这个注解来映射,否则取不到相应的值。

3.数据绑定(普通)

1.使用JavaBean绑定参数

Spring MVC会根据请求参数名和JavaBean属性名进行匹配,自动为对象填充属性值,同时支持级联属性(对象中包含对象)

Address

package com.xxx.entity;
import lombok.Data;
@Data
public class Address {
    private String value;
}

User类

package com.xxx.entity;
import lombok.Data;
//@Data注解,可以不用写getter与setter方法,需要添加依赖
@Data
public class User {
    private long id;
    private String name;
    private Address address;
}

register.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <form action="/user/save" method="post">
<%--        name:把这里的值与User中相匹配,必须对应--%>
        用户id:<input type="text" name="id"/><br/>
        用户名:<input type="text" name="name"/><br/>
<%--        address是个对象,要做级联操作--%>
        用户地址:<input type="text" name="address.value"/><br/>
        <input type="submit" value="注册">
    </form>
</body>
</html>

如果出现中文乱码问题,在web.xml中添加Spring MVC自带的过滤器即可

<!--    中文乱码要加过滤器-->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--        指定编码格式-->
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>

<!--    加一个映射,拦截所有请求-->
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

在pom.xml添加依赖,实现@Data这个注解

<!--    @Data注解,可以不用写getter与setter方法-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.6</version>
    <scope>provided</scope>
</dependency>

2.JSP页面的转发和重定向

1.区别
  • 转发:服务器跳转,地址栏不变,一次请求,可以取出存在请求里的数据。
  • 重定向:客户端跳转,地址栏改变,两次请求,不可以存在请求里的数据。

Spring MVC默认是转发的模式

2.转发
@RequestMapping("/forward")
public String forward(){
    return "forward:/index.jsp";
    // 二者等价
    // return "index";
}
3.重定向
@RequestMapping("/redirect")
    public String redirect(){
    return "redirect:/index.jsp";
}

4.Spring MVC数据绑定(全面)

1.概念

数据绑定:在后端的业务中直接获取客户端HTTP请求中的参数,将请求参数映射到业务方法的形参中,Spring MVC中的数据绑定是由HandlerAdapter来完成的。

2.基本数据类型

@RequestMapping("/baseType")
// 直接返回id值,而不是视图
@ResponseBody
public String baseType(int id){
    return id+"";
}

@ResponseBody表示Spring MVC会直接将业务方法的返回值响应给客户端,如果不加@ResponseBody注解,Spring MVC会将业务方法的返回值传递给DispatcherServlet,再由DispatcherServlet调用ViewResolver对返回值进行解析,映射JSP资源。

3.包装

@RequestMapping("/packageType")
@ResponseBody
public String packageType(Integer id){
    return id+"";
}

包装类可以接受null,当Http请求没有参数时,使用包装类定义形参的数据类型,程序不会抛异常。

4.@RequestParam

@RequestMapping("/packageType")
@ResponseBody
// @RequestParam:手动匹配,让请求参数和形参列表匹配
public String packageType(@RequestParam(value = "num",required = true,defaultValue = "0") Integer id){
    return id+"";
}
1.value:

将HTTP请求中的名为num的参数传给形参id

2.requried:

设置num为必填项,true表示必填,false表示非必填,可省略。

3.default=“0”

如果HTTP请求参数没有num参数,默认值为0

5.数组

//可省略多个@ResponseBody,直接认为是值,返回的是model
@RestController
@RequestMapping("/data")
public class DataBindHandler {
    @RequestMapping("/array")
    public String array(String[] name){
        String str = Arrays.toString(name);
        return str;
    }
}
@restController

表示该控制器会直接将业务方法的返回值响应给客户端,不进行视图解析

@Controller

表示该控制器的每一个业务方法的返回值交给视图解析器进行解析,如果只需要将数据响应给客户端,而不需要视图解析,则需要在对应的业务方法定义处添加**@ResponseBody**。

//可省略多个@ResponseBody,直接认为是值,返回的是model
@RestController
@RequestMapping("/data")
public class DataBindHandler {
    @RequestMapping("/array")
    public String array(String[] name){
        String str = Arrays.toString(name);
        return str;
    }
}

等于

@Controller
@RequestMapping("/data")
public class DataBindHandler {
    @RequestMapping("/array")
    @ResponseBody
    public String array(String[] name){
        String str = Arrays.toString(name);
        return str;
    }
}

6.集合 List

Spring MVC不支持对List类型的直接转化,需要对List进行包装。(mvc不支持对对象赋值,只能给对象的属相赋值)

  • 集合分装类

    import lombok.Data;
    import java.util.List;
    @Data
    public class UserList {
        private List<User> users;
        public List<User> getUsers() {
            return users;
        }
        public void setUsers(List<User> users) {
            this.users = users;
        }
    }
    
  • addList.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <form action="/data/list" method="post">
    <%--只能和属性映射,不能和list映射--%>
            用户1编号:<input type="text" name="users[0].id"/><br/>
            用户1名称:<input type="text" name="users[0].name"/><br/>
            用户2编号:<input type="text" name="users[1].id"/><br/>
            用户2名称:<input type="text" name="users[1].name"/><br/>
            用户3编号:<input type="text" name="users[2].id"/><br/>
            用户3名称:<input type="text" name="users[2].name"/><br/>
            <input type="submit" value="提交"/>
        </form>
    </body>
    </html>
    
  • 业务方法

    @RequestMapping("/list")
    public String list(UserList userList){
        StringBuffer str = new StringBuffer();
        for (User user:userList.getUsers()) {
            str.append(user);
        }
        return str.toString();
    }
    
  • 处理@responseBody中文乱码

    在spring mvc.xml中配置消息转换器

    <mvc:annotation-driven>
        <!-- 消息转换器,在responseBody传值出现乱码时,需要加这个-->
        <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>
    

7.map集合

  • 自定义封装类

    package com.xxx.entity;
    import lombok.Data;
    import java.util.Map;
    @Data
    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;
        }
    }
    

    可以不加get和set方法,但必须要下载lombox插件,和配置相关依赖。

  • 业务方法

    @RequestMapping("/map")
    public String map(UserMap userMap){
        StringBuffer str = new StringBuffer();
        for (String key: userMap.getUsers().keySet()) {
            User user = userMap.getUsers().get(key);
            str.append(user);
        }
        return str.toString();
    }
    
  • addMap.jsp

    <form action="/data/map" method="post">
        <%-- key值随便填 它把id和name取出来封装为一个user,再把user放在map中,并取名为key(a,b,c)--%>
        用户1编号:<input type="text" name="users['a'].id"/><br/>
        用户1名称:<input type="text" name="users['a'].name"/><br/>
        用户2编号:<input type="text" name="users['b'].id"/><br/>
        用户2名称:<input type="text" name="users['b'].name"/><br/>
        用户3编号:<input type="text" name="users['c'].id"/><br/>
        用户3名称:<input type="text" name="users['c'].name"/><br/>
        <input type="submit" value="提交"/>
    </form>
    

8.json

客户端放送了Json格式字符串,直接通过Spring MVC绑定到业务方法中

  • 处理Spring MVC无法加载静态资源,在web.xml中配置即可

    <!--spring mvc无法加载静态资源的处理-->
    <!--js请求不被拦截,不会交给dispatcherServlet处理-->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>
    
  • json.jsp代码:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
        <script src="js/jquery-3.6.0.min.js"></script>
    </head>
    <body>
        <script>
            $(function () {
                var  user = {
                    "id":1,
                    "name":"张三"
                };
                $.ajax({
                    //要请求的后台地址
                    url:"/data/json",
                    //把user转化为json格式
                    data:JSON.stringify(user),
                    //发送的请求
                    type:"POST",
                    //字符乱码
                    		    contentType:"application/json;charset=UTF-8",
                    //返回的格式
                    dataType:"JSON",
                    //回调函数,data指的是返回的数据
                    success:function (data) {
                        alert(data.id+"--"+data.name);
                    }
                });
            })
        </script>
    </body>
    </html>
    
  • 业务代码

    @RequestMapping("/json")
    //RequestBody:把客户端(前端)的数据(json)给我,然后赋给形参user(java对象),请求
    //ResponseBody:作响应的时候,把数据作为json格式返回给客户端
    //body与json相关
    public User json(@RequestBody User user){
        System.out.println(user);
        user.setId(6);
        user.setName("张六");
        return  user;
    }
    

    Spring MVC中的JSON和JavaBean的转换需要借助fastjson,需要在pom.xml引入相关依赖。

    <!--    把json转化为java对象-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.32</version>
    </dependency>
    

    同时,要在springmvc.xml中添加fastjson的配置

    <mvc:annotation-driven>
        <!-- 消息转换器,在responseBody传值出现乱码时,需要加这个-->
        <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.FastJsonHttpMessageConverter">        </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    

5.Spring MVC数据解析

1.JSP四大作用域对应的内置对象

  • pageContent
  • request
  • session
  • appication

模型数据 的绑定是由ViewResolver来完成的,实际开发中,我们需要添加模型数据再交给ViewResovler来绑定。

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

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

2.request中添加

1.Map
  • 业务代码:
@RequestMapping("/map")
public String map(Map<String,User> map){
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    //把user加入域对象中,在jsp里,从域对象中进行解析
    //map会自动传到视图里,并且放到request里,所以可以直接去取
    map.put("user",user);
    //把视图展示出来
    return "view";
};
  • view.jsp代码:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%--不忽略el表达式,就对el表达式进行解析--%>
    <%@ page isELIgnored="false"%>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <%--通过el表达式直接从作用域里取--%>
        ${requestScope.user};
    </body>
    </html>
    
2.Model
  • 业务代码:

    @RequestMapping("/model")
    public String model(Model model){
        User user  = new User();
        user.setId(1);
        user.setName("张三");
        //把键值对存在request中
        model.addAttribute("user",user);
        return "view";
    }
    
3.ModelAndView

一共8种,但推荐3种,后面的几种写复杂了。

//推荐
@RequestMapping("/modelAndView")
public ModelAndView modelAndView(){
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    ModelAndView modelAndView = new ModelAndView();
    //向modelAndView添加模型数据
    modelAndView.addObject("user",user);
    //向modelAndView添加视图信息名称
    modelAndView.setViewName("view");
    return modelAndView;
}

@RequestMapping("/modelAndView2")
public ModelAndView modelAndView2(){
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    ModelAndView modelAndView = new ModelAndView();
    //向modelAndView添加模型数据
    modelAndView.addObject("user",user);
    //向modelAndView添加视图信息名称
    //写的是完整的物理视图路径
    View view = new InternalResourceView("/view.jsp");
    modelAndView.setView(view);
    return modelAndView;
}
//推荐
@RequestMapping("/modelAndView3")
public ModelAndView modelAndView3(){
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    //直接在构造方法中添加视图信息
    ModelAndView modelAndView = new ModelAndView("view");
    //向modelAndView添加模型数据
    modelAndView.addObject("user",user);
    return modelAndView;
}

@RequestMapping("/modelAndView4")
public ModelAndView modelAndView4(){
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    View view = new InternalResourceView("/view.jsp");
    //直接在构造方法中添加视图信息
    ModelAndView modelAndView = new ModelAndView(view);
    //向modelAndView添加模型数据
    modelAndView.addObject("user",user);
    return modelAndView;
}


@RequestMapping("/modelAndView5")
public ModelAndView modelAndView5(){
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    Map<String,User> map = new HashMap<>();
    map.put("user",user);
    //直接在构造方法中添加视图信息
    ModelAndView modelAndView = new ModelAndView("view",map);
    return modelAndView;
}

@RequestMapping("/modelAndView6")
public ModelAndView modelAndView6(){
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    Map<String,User> map = new HashMap<>();
    map.put("user",user);
    View view = new InternalResourceView("/view.jsp");
    //直接在构造方法中添加视图信息
    ModelAndView modelAndView = new ModelAndView(view,map);
    return modelAndView;
}

//推荐
@RequestMapping("/modelAndView7")
public ModelAndView modelAndView7(){
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    //直接在构造方法中视图和数据模型,第一个是视图,第二、三个是数据,第二个是key值
    ModelAndView modelAndView = new ModelAndView("view","user",user);
    return modelAndView;
}

@RequestMapping("/modelAndView8")
public ModelAndView modelAndView8(){
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    View view = new InternalResourceView("/view.jsp");
    //直接在构造方法中视图和数据模型,第一个是视图,第二、三个是数据,第二个是key值
    ModelAndView modelAndView = new ModelAndView(view,"user",user);
    return modelAndView;
}
4.HttpServletRequest
  • 业务代码
@RequestMapping("/request")
public String request(HttpServletRequest request){
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    //原生方式
    request.setAttribute("user",user);
    return "view";
}
  • 需要添加servlet的相关依赖

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.0.1</version>
        <scope>provided</scope>
    </dependency>
    
5.@ModelAttribute
  • 定义一个方法,该方法专门用来返回要填充到数据模型的的对象

    // 优先业务方法执行,会向request中添加对象。
    @ModelAttribute
    public User getUser(){
        User user  = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
    

    等价于

    @ModelAttribute
    public void getUser(Map<String,User> map){
        User user  = new User();
        user.setId(1);
        user.setName("张三");
        //手动添加模型数据
        map.put("user",user);
    }
    
  • 业务方法中无需再处理模型数据,只需要返回视图即可。

    @RequestMapping("/modelAttribute")
    public String modelAttribute(){
        return "view";
    }
    

3.Session中添加数据

1.使用原生的servlet api
@RequestMapping("/session")
public String session(HttpServletRequest request){
    //从request中获得session
    HttpSession session = request.getSession();
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    session.setAttribute("user",user);
    return "view";
}

@RequestMapping("/session2")
//框架自动创建session对象
public String session2(HttpSession session){
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    session.setAttribute("user",user);
    return "view";
}
2.通过SessionAttribute()
  • 名字
@SessionAttributes(value = "user")
//多个
@SessionAttributes(value = {"user","address"})
public class ViewHandler {}

对于ViewHandler中所有业务方法,只要向request中添加key=“user”、key=“address”的对象时,Spring MVC会自动将数据添加到session中,保存key不变。

  • 类型
//通过的是类型
@SessionAttributes(types = User.class)
@SessionAttributes(types ={User.class, Address.class})
public class ViewHandler {}

对于ViewHandler中所有业务方法,只要向request中添加User,Address的对象时,Spring MVC会自动将数据添加到session中,保存key不变。

4.application

@RequestMapping("/application")
public String application(HttpServletRequest request){
    //从request中获得application
    ServletContext application = request.getServletContext();
    User user  = new User();
    user.setId(1);
    user.setName("张三");
    application.setAttribute("user",user);
    return "view";
}

6.Spring MVC自定义的数据转换器

数据转换器是指将客户端HTTP请求的参数转化为业务方法中定义的形参,自定义表示开发者可以设计自主转换的方式,HandlerAdapter已经提供了通用的转化,String转int,表单数据的封装。

但在特殊的业务情境下,HanderAdapter无法进行转换,需要开发者自定义转换器


1.String转Date

客户端输入String类型的数据“2019-03-3”,自定义转化器将该数据转为Data类型对象。

  • 创建DateConverter转换器,实现Converter接口

    package com.xxx.converter;
    import org.springframework.core.convert.converter.Converter;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    public class DateConverter implements Converter<String, Date> {
        private String pattern;
        public DateConverter(String pattern) {
            this.pattern = pattern;
        }
        @Override
        public Date convert(String s) {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(this.pattern);
            Date date = null;
            try{
                date = simpleDateFormat.parse(s);
            }catch (Exception e){
                e.printStackTrace();
            }
            return date;
        }
    }
    
  • 在springmvc.xml中配置转换器

    <!--        配置自定义转换器-->
        <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
            <property name="converters">
    <!--            配置多个-->
                <list>
                    <bean class="com.xxx.converter.DateConverter">
                        <constructor-arg type="java.lang.String" value="yyyy-MM-dd">						</constructor-arg>
                    </bean>
                </list>
            </property>
        </bean>
    <!--    conversion-service:对conversionService进行注册-->
        <mvc:annotation-driven conversion-service="conversionService">
            <!-- 消息转换器,在responseBody传值出现乱码时,需要加这个-->
            <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.FastJsonHttpMessageConverter"></bean>
            </mvc:message-converters>
        </mvc:annotation-driven>
    
    
  • addDate.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
        <head>
            <title>title</title>
        </head>
        <body>
            <form action="/converter/date" method="post">
                请输入日期:<input type="text" name="date">(yyyy-MM-dd)<br/>
                <input type="submit" value="提交">
            </form>
        </body>
    </html>
    
  • Hander

    package com.xxx.controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.Date;
    @RestController
    @RequestMapping("/converter")
    public class ConverterHander {
        @RequestMapping("/date")
        public String date(Date date){
            return date.toString();
        }
    }
    

2.String转Student

  • StudentConverter

    package com.xxx.converter;
    import com.xxx.entity.Student;
    import org.springframework.core.convert.converter.Converter;
    public class StudentConverter implements Converter<String, Student> {
        @Override
        public Student convert(String s) {
            String[] args = s.split("-");
            Student student = new Student();
            student.setId(Long.parseLong(args[0]));
            student.setName(args[1]);
            student.setAge(Integer.parseInt(args[2]));
            return student;
        }
    }
    
  • jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <form action="/converter/student" method="post">
            请输入学生信息:<input type="text" name="student">(id-name-age)<br/>
            <input type="submit" value="提交">
        </form>
    </body>
    </html>
    
    
  • springnvc.xml

    <!--        配置自定义转换器-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <!--            配置多个-->
            <list>
                <bean class="com.xxx.converter.DateConverter">
                    <constructor-arg type="java.lang.String" value="yyyy-MM-dd"></constructor-arg>
                </bean>
                <!--                对student的转换-->
                <bean class="com.xxx.converter.StudentConverter"></bean>
            </list>
        </property>
    </bean>
    <!--    conversion-service:对conversionService进行注册-->
    <mvc:annotation-driven conversion-service="conversionService">
        <!-- 消息转换器,在responseBody传值出现乱码时,需要加这个-->
        <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.FastJsonHttpMessageConverter"></bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    
  • Handler

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

7.Spring MVC REST

1.概述

  1. REST:Representational State Transfer,资源表现层状态转换,是目前主流的互联网架构.
  2. 特点:结构清晰、标椎规范、易于理解、便于扩展。
  • 资源(Resource)

    网络上的一个实体,或者说网络中具体存在的信息。可以使用URI(统一资源定位符) 指向它,每个资源都有对应的一个特定的URL。

  • 表现成(Representation)

    资源具体呈现出来的形式,比如文本可以用tet格式表示,也可以是HTML、XML等表示。

  • 状态转换(State Transfer)

    客户端如果希望操作服务器的某个资源,就需要通过某种方式让服务端发生状态转换,而这种转换建立在表现层之上,所以叫做“表现层转态转换“。(具体资源生成URL,然后访问)

  • 特点

    1. URL更加简便
    2. 有利于不同系统之间的资源共享,只需要遵守一定的规范,不需要进行配置即可实现资源共享。

2.具体使用

REST具体操作就是HTTP协议中四个表示操作方式的动词分别对应的CRUD基本操作。

GET用来表示获取资源

POST用来表示新建资源

PUT用来表示修改资源

DELETE用来表示删除资源

  • Handler

    package com.xxx.controller;
    import com.xxx.entity.Student;
    import com.xxx.repository.StudentRepository;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import javax.servlet.http.HttpServletResponse;
    import java.util.Collection;
    
    @RestController
    @RequestMapping("/rest")
    public class RestHandler {
        //根据类型去注入
        @Autowired
        private StudentRepository studentRepository;
    //    @RequestMapping(value = "/findAll",method = RequestMethod.GET)
    //    二者等价
        @GetMapping("/findAll")
        public Collection<Student> findALL(HttpServletResponse response){
            //配置文件里可以解决异步请求,这里的配置可以解决同步请求。
    
            response.setContentType("text/json;charset=UTF-8");
            return studentRepository.findAll();
        }
        @GetMapping("/findById/{id}")
    //    通过@PathVarible注解完成请求参数与形参的映射,
    //    在RESTful风格中,这个注解必须存在,否则就无法完成映射,这一点与传统风格不同。
    //如果他们请求参数与形参一致,就可以不用写value的值,即直接写@PathVariable即可。
        public  Student findById(@PathVariable("id") long id){
            return studentRepository.findById(id);
        }
    
        @PostMapping("/save")
        //把客户端(前端)的数据(json)给我,然后赋给形参(java对象)
        public void save(@RequestBody Student student){
            studentRepository.saveOrUpdate(student);
        }
    
        @PutMapping("/update")
        public void update(@RequestBody Student student){
            studentRepository.saveOrUpdate(student);
        }
    
        @DeleteMapping("/deleteById/{id}")
        public void  deleteById(@PathVariable("id") long id){
             studentRepository.deleteById(id);
        }
    }
    
  • StudentRepository

    package com.xxx.repository;
    import com.xxx.entity.Student;
    import java.util.Collection;
    public interface StudentRepository {
        public Collection<Student> findAll();
        public Student findById(long id);
        public void saveOrUpdate(Student student);
        public void deleteById(long id);
    }
    
    
  • StudentRepositoryImpl

    package com.xxx.repository.impl;
    import com.xxx.entity.Student;
    import com.xxx.repository.StudentRepository;
    import org.springframework.stereotype.Repository;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    
    @Repository
    public class StudentRepositoryImpl implements StudentRepository {
        private static Map<Long,Student> studentMap;
        static {
            studentMap = new HashMap<>();
            studentMap.put(1L,new Student(1L,"张三",22));
            studentMap.put(2L,new Student(2L,"李四",23));
            studentMap.put(3L,new Student(3L,"王五",24));
        }
    
        @Override
        public Collection<Student> findAll() {
            return studentMap.values();
        }
    
        @Override
        public Student findById(long id) {
            return studentMap.get(id);
        }
    
        @Override
        public void saveOrUpdate(Student student) {
            studentMap.put(student.getId(),student);
        }
    
        @Override
        public void deleteById(long id) {
            studentMap.remove(id);
        }
    }
    

8.Spring MVC文件的上传下载

1.上传

1.单个文件的上传

底层是使用Apache fileupload组件完成上传,Spring MVC对这种方式进行了封装。

  • 在pom.xml文件中添加相关依赖

    <!--      文件上传要添加的依赖-->
    <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.3</version>
    </dependency>
    
  • 在springmvc.xml中配置上传组件

    <!--    配置上传组件-->
        <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
    
  • jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%--不忽略el表达式--%>
    <%@ page isELIgnored="false" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <%--method="post" enctype="multipart/form-data" 是必须的,如果是get,则只能把文件名上传上去--%>
        <form action="/file/upload" method="post" enctype="multipart/form-data">
            <input type="file" name="img">
            <input type="submit" value="上传">
        </form>
        <img src="${path}">
    </body>
    </html>
    
    1. input的type设置为file
    2. form的method设置为post(get请求只能将文件名上传给服务器)
    3. form的enctype设置为multipart-form-data(如果不设置只能将文件名上传给服务器)
  • handler

    package com.xxx.controller;
    
    

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;

@Controller
@RequestMapping("/file")
public class fileGHandler {
@PostMapping("/upload")
//MultipartFile:对前台传来的二进制数据进行封装
public String upload(MultipartFile img, HttpServletRequest request){
// System.out.println(img);
if (img.getSize()>0){
//上传文件的要保存的file文件夹的路径,把数据全部放到file文件里
//去tomcat中去找这个file文件夹,手动创建的话一定要有内容才能去识别

          String path = request.getServletContext().getRealPath("file");
          //获取上传文件名
          String name = img.getOriginalFilename();
          //在path路径下创建name文件
          File file = new File(path,name);
          try {
              //把img对象中的数据传给新建的文件夹中
              img.transferTo(file);
              //把图片所在的路径的路径传给request中
              request.setAttribute("path","/file/"+name);
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
      return "upload";
  }

}


* 在web.xml添加代码,处理无法加载.jpg图片

 ~~~xml
<servlet-mapping>
  <servlet-name>default</servlet-name>
  <url-pattern>*.jpg</url-pattern>
</servlet-mapping>
2.多文件上传
  • pom.xml,添加jstl依赖

    <dependency>
        <groupId>jstl</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
    
    <dependency>
        <groupId>taglibs</groupId>
        <artifactId>standard</artifactId>
        <version>1.1.2</version>
    </dependency>
    
  • jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%--不忽略el表达式--%>
    <%@ page isELIgnored="false" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <%--method="post" enctype="multipart/form-data" 是必须的,如果是get,则只能把文件名上传上去--%>
        <form action="/file/upload" method="post" enctype="multipart/form-data">
            <input type="file" name="img">
            <input type="submit" value="上传">
        </form>
    
        <c:forEach items="${files}" var="file">
            <img src="${file}" width="200px">
        </c:forEach>
    </body>
    </html>
    
  • Handler

    @PostMapping("/uploads")
    public String uploads(MultipartFile[] imgs, HttpServletRequest request){
        List<String> files = new ArrayList<>();
        for (MultipartFile img:imgs) {
            if (img.getSize()>0){
                //上传文件的要保存的file文件夹的路径,把数据全部放到file文件里
                //去tomcat中去找这个file文件夹,手动创建的话一定要有内容才能去识别
    
                String path = request.getServletContext().getRealPath("file");
                //获取上传文件名
                String name = img.getOriginalFilename();
                //在path路径下创建name文件
                File file = new File(path,name);
                try {
                    //把img对象中的数据传给新建的文件夹中
                    img.transferTo(file);
                    files.add("/file/"+name);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        request.setAttribute("files",files);
        return "upload";
    }
    

2.下载

  • jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <a href="/file/download/10">1.jpg</a><br/>
    <a href="/file/download/11">2.jpg</a><br/>
    <a href="/file/download/12">3.jpg</a><br/>
</body>
</html>
  • Handler

    @GetMapping("/download/{name}")
    public void download(@PathVariable String name, HttpServletRequest request, HttpServletResponse response){
        if (name != null){
            name+=".jpg";
            String path = request.getServletContext().getRealPath("file");
            File file = new File(path,name);
            OutputStream outputStream = null;
            if (file.exists()){
                //做些下载的设置,并且指定下载的文件名。
                response.setContentType("application/forc-download");
                response.setHeader("Content-Disposition","attachment;filename="+name);
                try {
                    outputStream = response.getOutputStream();
                    //把file转变为数组
                    outputStream.write(FileUtils.readFileToByteArray(file));
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    if (outputStream != null){
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    

9.Spring MVC表单标签库

1.基本使用

  • Handler

    @GetMapping("get")
    public ModelAndView modelAndView(){
        ModelAndView modelAndView = new ModelAndView("tag");
        Student student = new Student(1,"张三",22);
        modelAndView.addObject("student",student);
        return modelAndView;
    }
    
  • jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ page isELIgnored="false" %>
    <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <h1>学生信息</h1>
        <form:form modelAttribute="student">
            学生ID:<form:input path="id"></form:input><br/>
            学生姓名:<form:input path="name"></form:input><br/>
            学生年龄:<form:input path="age"></form:input><br/>
            <input type="submit" value="提交">
        </form:form>
    </body>
    </html>
    
  1. Jsp页面导入Spring MVC表单标签库,与导入JSTL标签库的语法非常相似,前缀prefix可以自定义,通常定义为form。

    <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
    
  2. 将form表单与模型数据进行绑定,通过modelAttribute属性完成绑定,将modelAtrribute的值设置为模型数据对应的key值。

    jsp: 	  <form:form modelAttribute="student">
    handler: modelAndView.addObject("student",student);
    
  3. form表单完成绑定之后,将模型数据的值取出绑定不同的标签中,通过设置标签的path属性完成,将path属性的值设置为模型数据对应的属性名即可。

    学生ID:<form:input path="id"></form:input><br/>
    学生姓名:<form:input path="name"></form:input><br/>
    学生年龄:<form:input path="age"></form:input><br/>
    

2.常用的表单标签

1.form
<form:from modelAttribute="student"/>

渲染的HTML中的<form></form>,通过modelAttibute属性绑定具体的模型数据。

2.input
<form:input path="name"/>

渲染的是HTML中的<input type="text"/>,form标签绑定的是模型数据,input标签绑定的是模型数据中的属性值,通过path属性可以与模型数据中的属性名对应,并支持级联操作

<from:input path="address.name"/>
3.password
<form:password path="password"/>

渲染的是HTML中的<input type="password"/>,通过path属性与模型数据的属性值进行绑定,passwor标签的值不会在页面显示。

4.checkbox
<%--value是复选框所代表的值--%>
checkbox:<form:checkbox path="flag" value="flag"></form:checkbox><br/>

渲染的是HTML中的<input type="checkbox/>",通过path与模型数据的属性值进行绑定,可以绑定boolean、数组和集合。

如果绑定boolean值,若 该变量的值为true,则表示该复选框选中,否则表示不选中。

如果绑定数组或者集合,数组、集合中的元素等于checkbox的value的值,则选中,否则就不选中。

String[] hobbies = {"读书","看电影","做笔记","玩游戏"};
student.setHobbies(hobbies);
modelAndView.addObject("student",student);

jsp:

爱好:<br/>
<form:checkbox path="hobbies" value="读书"/>读书<br/>
<form:checkbox path="hobbies" value="看电影"/>看电影<br/>
<form:checkbox path="hobbies" value="做笔记"/>做笔记<br/>
<form:checkbox path="hobbies" value="玩游戏"/>玩游戏<br/>
<input type="submit" value="提交">
5.checkboxs
<form:checkboxes items={student.hobbies} path="selectHoby"/>

渲染的是HTML的一组<input type="checkbox"/>,是对<form:checkbox/>的一种简化,需要结合items和path属性来使用,items绑定被遍历的集合或数组,path绑定被选中的集合或数组,可以理解为,items为全部可选集合,path为默认的选中的集合。

  • handler
List hobbylist = Arrays.asList("读书","看电影","做笔记","玩游戏");
student.setHobbies(hobbylist);
List selectHobby = Arrays.asList("读书","看电影","做笔记");
student.setSelectHobby(selectHobby);
modelAndView.addObject("student",student);
  • jsp:
爱好: <form:checkboxes path="selectHobby" items="${student.hobbies}"/><br/>

需要注意的是:path可以直接绑模型数据的属性值,items则需要通过EL表达式的形式从域对象中获取数据,不能直接写属性名。

6.radiobutton
<from:radiobutton path="radioId" value=0/>

渲染的是HTML中的一个 <input type="radio"/>,绑定的数据与标签的value值相等则为选中,否则不选中。

  • handler

    student.setRadioId(1);
    modelAndView.addObject("student",student);
    
  • jsp

    rediobutton:<form:radiobutton path="radioId" value="1"></form:radiobutton>radiobutton<br/>
    
7.radiobuttons
<form:radiobuttons items="${student.grade} path="selectGrade"/>

渲染的是HTML中的一组<input type="radio"/>,这里需要结合items和path两个属性使用,items绑定被遍历的结合或数组,path被选中的值,items为全部可选类型,path为默认 选中的选项,用法和<form:checkboxes/>一致。

  • handler:

    Map<Integer,String> gradeMap = new HashMap<>();
    gradeMap.put(1,"一年级");
    gradeMap.put(2,"二年级");
    gradeMap.put(3,"三年级");
    gradeMap.put(4,"四年级");
    gradeMap.put(5,"五年级");
    gradeMap.put(6,"六年级");
    student.setGradeMap(gradeMap);
    student.setSelectGrade(3);
    modelAndView.addObject("student",student);
    
  • jsp

 学生年级:<form:radiobuttons path="selectGrade" items="${student.gradeMap}"></form:radiobuttons><br/>
  • 最终的studnet类

    package com.xxx.entity;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import java.util.List;
    import java.util.Map;
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Student {
        private long id;
        private String name;
        private int age;
        private boolean flag;
        private String[] hobbies;
        private List<String> selectHobby;
        private  int radioId;
        private Map<Integer,String> gradeMap;
        private int selectGrade;
        public Student(long id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
    }
    
8.select
 <form:select items="${student.cities} path="selectCity"/>

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

  • handler
Map<Integer,String> cityMap = new HashMap<>();
cityMap.put(1,"北京");
cityMap.put(2,"上海");
cityMap.put(3,"广州");
cityMap.put(4,"南京");
cityMap.put(5,"深圳");
student.setCityMap(cityMap);
student.setSelectCity(2);
  • jsp

     地址:<form:select path="selectCity" items="${student.cityMap}"></form:select><br/>
    
9.options

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

所在城市:<form:select path="selectCity">
    <form:options items="${student.cityMap}"></form:options>
</form:select><br/>
10.option

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

所在城市:<form:select path="selectCity">
    <form:option value="1">杭州</form:option><br>
    <form:option value="2">成都</form:option><br>
    <form:option value="3">西安</form:option><br>
</form:select>

这个是在前端写,而optionss是后端写的。

11.textarea

渲染的是HTML中的<textarea/>,path绑定模型数据的属性值,作为文本输入框的默认值。

  • handler

    student.setIntroduce("您好,我是xxx");
    modelAndView.addObject("student",student);
    
  • jsp

     自我介绍:<form:textarea path="introduce"/><br/>
    
12.errors

用来处理错误信息,一般用在数据校验这部分,该标签需要结合Spring MVC的验证结合起来使用

10.Spring MVC数据校验

Spring MVC提供了两种校验方式:

  • 基于Valibdator接口
  • 使用AnnotationJSR-303标椎进行校验。

基于Validator接口的需要自定义Validator验证器,每一条的验证规则需要开发者手动完成,使用AnotationJSR-303标准则不需要自定义验证器,通过注解的方式可以直接在实体类中添加每个属性的验证规则,这种方式更加方便,实际开发中推荐使用。

1.基于Valibdator接口

  • 实体类Account

    package com.xxx.entity;
    import lombok.Data;
    @Data
    public class Account {
        private  String name;
        private  String password;
    }
    
  • 自定义验证器AccountValidation,实现Validator接口

    package com.xxx.validator;
    import com.xxx.entity.Account;
    import org.springframework.validation.Errors;
    import org.springframework.validation.ValidationUtils;
    import org.springframework.validation.Validator;
    public class AccountValidator implements Validator {
        //是否支持这种类型,true就就验证,false就不去验证。
        @Override
        public boolean supports(Class<?> aClass) {
            return Account.class.equals(aClass);
        }
    
        @Override
        public void validate(Object o, Errors errors) {
    //        name为空就提示报错信息:姓名不能为空
            ValidationUtils.rejectIfEmpty(errors,"name","","姓名不能为空");
            ValidationUtils.rejectIfEmpty(errors,"password","","密码不能为空");
        }
    }
    
    
  • Handler

    package com.xxx.controller;
    
    import com.xxx.entity.Account;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.validation.BindingResult;
    import org.springframework.validation.annotation.Validated;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    @RequestMapping("/validator")
    public class ValidatorHandler {
        @GetMapping("/login")
        public String login(Model model){
            model.addAttribute("account",new Account());
            return "login";
        }
    
        @PostMapping("/login")
    //@Validated:启用验证器,BindingResult:绑定结果集
        public String login(@Validated Account account, BindingResult bindingResult){
            if (bindingResult.hasErrors()){
                return "login";
            }
            return "index";
        }
    }
    
    
  • springmvc.xml中配置验证器,否则不生效。

    <!--配置Validator的配置-->
    <bean id="accountValidator" class="com.xxx.validator.AccountValidator"></bean>
    <mvc:annotation-driven validator="accountValidator"></mvc:annotation-driven>
    
  • jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ page isELIgnored="false" %>
    <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <form:form modelAttribute="account" action="/validator/login" method="post">
            姓名:<form:input path="name"/><form:errors path="name"/><br/>
            年龄:<form:input path="password"/><form:errors path="password"/>br/>
            <input type="submit" value="登录">
        </form:form>
    </body>
    </html>
    

2.AnnotationJSR-303标椎

使用AnotationJSR-303标椎进行验证,需要导入支持这种标椎的依赖jar文件,这里我们使用HibenateValidator。

  • pom.xml

    <!--JSR-303,数据验证-->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>5.3.6.Final</version>
    </dependency>
    
    <dependency>
        <groupId>javax.validation</groupId>
        <artifactId>validation-api</artifactId>
        <version>1.1.0.Final</version>
    </dependency>
    
    <dependency>
        <groupId>org.jboss.logging</groupId>
        <artifactId>jboss-logging</artifactId>
        <version>3.3.0.Final</version>
    </dependency>
    
  • 通过注解的方式直接在实体类中添加验证规则 。

package com.xxx.entity;
import lombok.Data;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

@Data
public class Person {
    @NotEmpty(message = "用户名不能为空")
    private String username;
    @Size(min = 6,max = 12,message = "密码6-12位")
    private  String password;
    @Email(regexp = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$",message = "请输入正确的邮箱格式")
    private String email;
    @Pattern(regexp = "^(13[0-9]|14[5|7]|15[0|1||3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$",message = "请输入正确的电话")
    private String phone;
}

  • ValidatorHandler
@GetMapping("/register")
public String register(Model model){
    model.addAttribute("person",new Person());
    return "register";
}

@PostMapping("/register")
public String register(@Valid Person person, BindingResult bindingResult){
    if (bindingResult.hasErrors()){
        return "register";
    }
    return "index";
}
  • springmvc.xml

    <!--    需要重新写一次-->
    <mvc:annotation-driven></mvc:annotation-driven>
    

    让注解驱动生效

  • jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ page isELIgnored="false" %>
    <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <form:form modelAttribute="person" action="/validator/register2" method="post">
            用户名:<form:input path="username"></form:input><form:errors path="username"/> <br/>
              密码:<form:password path="password"></form:password><form:errors path="password"/> <br/>
              邮箱:<form:input path="email"></form:input><form:errors path="email"/> <br/>
              电话:<form:input path="phone"></form:input><form:errors path="phone"/> <br/>
            <input type="submit" value="提交">
        </form:form>
    </body>
    </html>
    
  • 相关注解

    1. @Null 被注解的元素必须为null
    2. @NotNUll 被注解的元素不能为null
    3. @Min(value) 被注解的元素不许是一个数字,其值必须大于等于指定的值
    4. @Max(vale) 被注解的元素必须是一个数字,其值必须大于等于指定的最小值
    5. Email 被注解的值必须是电子邮箱的地址
    6. Pattern 被注解的元素必须符合对应的正则表达式
    7. Length 被注解的元素的大小必须在指定的范围内
    8. NotEmpty 被注解的字符串必须非空

    Null与Empty是不同的结果,String str = null,str是null,String str ="",str不是null,其值为空。

private String password;
@Email(regexp = “^\w+([-+.]\w+)@\w+([-.]\w+)\.\w+([-.]\w+)* " , m e s s a g e = " 请 输 入 正 确 的 邮 箱 格 式 " ) p r i v a t e S t r i n g e m a i l ; @ P a t t e r n ( r e g e x p = " ( 13 [ 0 − 9 ] ∣ 14 [ 5 ∣ 7 ] ∣ 15 [ 0 ∣ 1 ∣ ∣ 3 ∣ 5 ∣ 6 ∣ 7 ∣ 8 ∣ 9 ] ∣ 18 [ 0 ∣ 1 ∣ 2 ∣ 3 ∣ 5 ∣ 6 ∣ 7 ∣ 8 ∣ 9 ] ) d 8 ",message = "请输入正确的邮箱格式") private String email; @Pattern(regexp = "^(13[0-9]|14[5|7]|15[0|1||3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8} ",message="")privateStringemail;@Pattern(regexp="(13[09]14[57]15[01356789]18[012356789])d8”,message = “请输入正确的电话”)
private String phone;
}


* ValidatorHandler

~~~java
@GetMapping("/register")
public String register(Model model){
    model.addAttribute("person",new Person());
    return "register";
}

@PostMapping("/register")
public String register(@Valid Person person, BindingResult bindingResult){
    if (bindingResult.hasErrors()){
        return "register";
    }
    return "index";
}
  • springmvc.xml

    <!--    需要重新写一次-->
    <mvc:annotation-driven></mvc:annotation-driven>
    

    让注解驱动生效

  • jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <%@ page isELIgnored="false" %>
    <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <form:form modelAttribute="person" action="/validator/register2" method="post">
            用户名:<form:input path="username"></form:input><form:errors path="username"/> <br/>
              密码:<form:password path="password"></form:password><form:errors path="password"/> <br/>
              邮箱:<form:input path="email"></form:input><form:errors path="email"/> <br/>
              电话:<form:input path="phone"></form:input><form:errors path="phone"/> <br/>
            <input type="submit" value="提交">
        </form:form>
    </body>
    </html>
    
  • 相关注解

    1. @Null 被注解的元素必须为null
    2. @NotNUll 被注解的元素不能为null
    3. @Min(value) 被注解的元素不许是一个数字,其值必须大于等于指定的值
    4. @Max(vale) 被注解的元素必须是一个数字,其值必须大于等于指定的最小值
    5. Email 被注解的值必须是电子邮箱的地址
    6. Pattern 被注解的元素必须符合对应的正则表达式
    7. Length 被注解的元素的大小必须在指定的范围内
    8. NotEmpty 被注解的字符串必须非空

    Null与Empty是不同的结果,String str = null,str是null,String str ="",str不是null,其值为空。

学习视频:https://www.bilibili.com/video/BV1GE411d7KE

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值