Spring MVC

入门案例

案例实现

步骤1

  • 导入坐标


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0modelVersion>

  <groupId>org.examplegroupId>
  <artifactId>SpringMVC_textartifactId>
  <version>1.0-SNAPSHOTversion>
  <packaging>warpackaging>


  <properties>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    <maven.compiler.source>1.8maven.compiler.source>
    <maven.compiler.target>1.8maven.compiler.target>
  properties>

  <dependencies>
    <dependency>
      <groupId>javax.servletgroupId>
      <artifactId>javax.servlet-apiartifactId>
      <version>3.1.0version>
      <scope>providedscope>
    dependency>
    <dependency>
      <groupId>javax.servlet.jspgroupId>
      <artifactId>jsp-apiartifactId>
      <version>2.1version>
      <scope>providedscope>
    dependency>
    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-contextartifactId>
      <version>5.1.9.RELEASEversion>
    dependency>
    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-webartifactId>
      <version>5.1.9.RELEASEversion>
    dependency>
    
    <dependency>
      <groupId>org.springframeworkgroupId>
      <artifactId>spring-webmvcartifactId>
      <version>5.1.9.RELEASEversion>
    dependency>
  dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.tomcat.mavengroupId>
        <artifactId>tomcat7-maven-pluginartifactId>
        <version>2.1version>
        <configuration>
          <port>80port>
          <path>/path>
        configuration>
      plugin>
    plugins>
  build>
project>

步骤2

  • 定义表现层业务处理器controller,并配置成spring的bean(等同于servlet)
package com.liu.controller;

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

@Controller
public class UserController {
    public String save(){
        System.out.println("user mvc controller is running ...... ");
    }
}
  • 该bean的处理需要使用独立的配置文件扫描(XML版)(spring-mvc.xml

<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"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        ">
        
    <context:component-scan base-package="com.liu" />

beans>

步骤3

  • web .xml中配置springMvc核心控制器,用于将请求转发到对应的具体业务处理器controller中(等同于servlet配置)

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    
    <servlet>
        <servlet-name>DispatcherServletservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>classpath*:spring-mvc.xmlparam-value>
        init-param>
    servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServletservlet-name>
        <url-pattern>/url-pattern>
    servlet-mapping>

web-app>

步骤4

  • 设定具体controller的访问路径(等同于servlet在web. xml中的配置)
package com.liu.controller;

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

@Controller
public class UserController {
    @RequestMapping("/save")
    public String save(){
        System.out.println("user mvc controller is running ...... ");
    }
}

步骤5

  • 设置返回页面
package com.liu.controller;

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

@Controller
public class UserController {
    @RequestMapping("/save")
    public String save(){
        System.out.println("user mvc controller is running ...... ");
        return "success.jsp";	
    }
}

入门案例工作流程分析

  • 服务器启动
    1. 加载web.xrn1中Dispatcherservlet
    2. 读取spring-mvc.xml中的配置,加载所有com.itheima包中所有标记为bean的类
    3. 读取bean中方法上方标注@RecuestMapping的内容
  • 处理请求
    1. DispatcherServlet配置拦截所有请求 /
    2. 使用请求路径与所有加载的@RecuestMapping的内容进行比对
    3. 执行对应的方法
    4. 根据方法的返回值在webapp目录中查找对应的页面并展示

SpringMVC 技术架构图

  • Dispatcherservlet:前端控制器,是整体流程控制的中心,由其调用其它组件处理用户的请求,有效的降低了组件间的耦合性
  • HardlerMapping:处理器映射器,负责根据用户请求找到对应具体的Handler处理器
  • Handler:处理器,业务处理的核心类,通常由开发者编写,描述具体的业务
  • HardlAdaptez:处理器适配器,通过它对处理器进行执行
  • View Resolver:视图解析器,将处理结果生成view视图
  • view:视图,最终产出结果,常用视图如jsp、 html

基础配置

Controller加载控制

  • SpringMVC的处理器对应的bean必须按照规范格式开发,为避免加入无效的bean可通过bean加载过滤器进行包含设定或排除设定,表现层bean标注通常设定为@Controller

spring-mvc.xml文件中修改成

<context:component-scan base-package="com.liu">
	<context:include-filter
		type="annotation"
		expression="osg.springframework .stereotype.Controller" />
context:component-scan>

或者在SpringMVCConfig.java文件中修改成

package com.liu.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(
        value = "com.liu",
        includeFilters =
                @ComponentScan.Filter(
                        type = FilterType.ANNOTATION,
                        classes = {Controller.class}
                )
)
public class SpringMVCConfig {
}

静态资源加载控制

  • 核心控制器拦截的是所有请求,需要对静态资源请求进行放行,通过配置放行资源实现
<mvc:resources mapping="/img/**" 1ocation="/ing/" />
<mvc:resources mapping="/js/**" location="/js/" />
  • 使用简化格式可以放行所有普通资源调用,无需一一枚举
<mve: default-servlet-handler />

spring-mvc.xml文件中修改成


<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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
        ">
    <context:component-scan base-package="com.liu" >
        
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    context:component-scan>

    




    
    <mvc:default-servlet-handler />
beans>

或者在SpringMVCConfig.java文件中修改成

package com.liu.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@ComponentScan(
        value = "com.liu",
        includeFilters =
                @ComponentScan.Filter(
                        type = FilterType.ANNOTATION,
                        classes = {Controller.class}
                )
)
public class SpringMVCConfig implements WebMvcConfigurer {
//    @Override
//    public void addResourceHandlers(ResourceHandlerRegistry registry) {
//        // 静态资源加载控制
//        registry.addResourceHandler("/img/**").addResourceLocations("/img/");
//        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
//        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
//    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        // 简化:静态资源加载控制
        configurer.enable();
    }
}

中文乱码处理

  • SpringMVC 提供专用的中文字符过滤器,用于处理乱码问题
<filter>
	<filter-name>characterEncodingFilterfilter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-olass>
	<init-paran>
		<paran-name>encodingparan-nane>
		<param-value>UTF-8paran-value>
	init-param>
filter>
<filter-mapping>
	<filter-name>characterEncodingFilterfi1ter-name>
	<uri-pattern>/*ur1-pattern>
fi1ter-mapping>

在 web.xml 中加上


<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    
    <filter>
        <filter-name>characterEncodingFilterfilter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
        <init-param>
            <param-name>encodingparam-name>
            <param-value>UTF-8param-value>
        init-param>
    filter>
    <filter-mapping>
        <filter-name>characterEncodingFilterfilter-name>
        <url-pattern>/*url-pattern>
    filter-mapping>
    
    <servlet>
        <servlet-name>DispatcherServletservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        <init-param>
            <param-name>contextConfigLocationparam-name>
            <param-value>classpath*:spring-mvc.xmlparam-value>
        init-param>
    servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServletservlet-name>
        <url-pattern>/url-pattern>
    servlet-mapping>

web-app>

或者在

package com.liu.config;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.EnumSet;

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {

    @Override
    protected WebApplicationContext createServletApplicationContext() {
//    
//        DispatcherServlet
//        org.springframework.web.servlet.DispatcherServlet
//        
//            contextConfigLocation
//            classpath*:spring-mvc.xml
//        
//    
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringMVCConfig.class);
        return ctx;
    }

    @Override
    protected String[] getServletMappings() {
//        
//            DispatcherServlet
//            /
//        
        return new String[]{"/"};
    }

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
//    
//        characterEncodingFilter
//        org.springframework.web.filter.CharacterEncodingFilter
//        
//            encoding
//            UTF-8
//        
//    
//    
//        characterEncodingFilter
//        /*
//    

		// 中文乱码处理
		// 调用父类的onStartup
		super.onStartup(servletContext);
		// 1.创建字符集过滤器对象
        CharacterEncodingFilter cef = new CharacterEncodingFilter();
        // 2.设置使用的字符集
        cef.setEncoding("UTF-8");
        // 3.添加到容器(它不是ioc容器,而是ServletContainer)
        FilterRegistration.Dynamic registration = servletContext.addFilter("characterEncodingFilter", cef);
		// 4.添加映射
		registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST,DispatcherType.FORWARD,DispatcherType.INCLUDE),false,"/*");
    }
}

请求

服务器端要获得请求的参数,有时还需要进行数据的封装,SpringMVC可以接收如下类型的参数:

  • 基本类型参数
  • POJO类型参数
  • 数组类型参数
  • 集合类型参数

获得基本类型参数

Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。
http://localhost:8080/quick9?username=zhangsan&age=12
在业务层中

package com.liu.controller;

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

import java.io.IOException;

@Controller
public class UserController {
    
    ......

    @RequestMapping("/quick9")
    @ResponseBody    //不进行页面跳转(说明:直接回写数据方式返回)
    public void quickMethod9(String username,int age) throws IOException {
        System.out.println(username);
        System.out.println(age);
    }
}

获得POJO类型参数

Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配。
http://localhost:8080/quick9?username=zhangsan&age=12
要有User实体类(因为要自动映射匹配)

package com.liu.domain;

public class User {
    private String username;
    private int age;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}

在业务层中

package com.liu.controller;

import com.liu.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;

@Controller
public class UserController {
    
    ......
    
    @RequestMapping("/quick10")
    @ResponseBody    //不进行页面跳转(说明:直接回写数据方式返回)
    public void quickMethod10(User user) throws IOException {
        System.out.println(user);
    }
}

获得数组类型参数

Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配。
http://localhost:8080/quick11?strs=111&strs=222&strs=333
在业务层中

package com.liu.controller;

import com.liu.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.util.Arrays;

@Controller
public class UserController {
    
    ......

    @RequestMapping("/quick11")
    @ResponseBody    //不进行页面跳转(说明:直接回写数据方式返回)
    public void quickMethod11(String[] strs) throws IOException {
        System.out.println(Arrays.asList(strs));
    }
}

获得集合类型参数

  • 场景一:
    获得集合参数时,要将集合参数包装到一个POJO中才可以。
    post : userList[0].username=zzz & userList[0].age=18 & userList[1].username=aaa & userList[1].age=20
    创建VO实体类(放置 userList 集合)
package com.liu.domain;

import java.util.List;

public class VO {
    private List<User> userList;

    public List<User> getUserList() {
        return userList;
    }

    public void setUserList(List<User> userList) {
        this.userList = userList;
    }

    @Override
    public String toString() {
        return "VO{" +
                "userList=" + userList +
                '}';
    }
}

在业务层中

package com.liu.controller;

import com.liu.domain.User;
import com.liu.domain.VO;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.util.Arrays;

@Controller
public class UserController {
    
    ......

    @RequestMapping("/quick12")
    @ResponseBody    //不进行页面跳转(说明:直接回写数据方式返回)
    public void quickMethod12(VO vo) throws IOException {
        System.out.println(vo);
    }
}
  • 场景二:
    当使用ajax提交时,可以指定contentType为json形式,那么在方法参数位置使用@RequestBody可以直接接收集合数据而无需使用POJO进行包装。

在前端中

<%@ page contentType="text/htm1 ; charset=UTF-8" language="java"%>
<html>
	<head>
		<title>Titletitle>
		<script src="$ lpageContext.request.contextPath/js/jquery-3.3.1.js">script><script>
			var userList = new Array();
			userList.push({username:"zhangsan",age:18});
			userList.push({username:"lisi",age:28});
			$.ajax ({
				type:"POST",
				ur1:"$ {pageContext.request.contextPath)/quick13",
				data:JSON.stringify(userList),
				contentType:"app1icationljson; charset=utf-8"
			});
		script>
	head>
<body>
body>
html>

在业务层中

package com.liu.controller;

import com.liu.domain.User;
import com.liu.domain.VO;
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.io.IOException;
import java.util.Arrays;
import java.util.List;

@Controller
public class UserController {
    
    ......

    @RequestMapping("/quick13")
    @ResponseBody    //不进行页面跳转(说明:直接回写数据方式返回)
    public void quickMethod13(@RequestBody List<User> userList) throws IOException {
        System.out.println(userList);
    }
}

异步请求传参

  • 名称:@RequestBody
  • 类型:形参注解
  • 位置:处理器类中的方法形参前方
  • 作用:将异步提交数据组织成标准请求参数格式,并赋值给形参
  • 范例:
@RequestMapping ("/ajaxController")
public string ajaxController(@RequestBody String message){
	system.out.println(message);
	return "page.jsp";
}

响应

SpringMVC的数据响应方式

  • 页面跳转
    • 直接返回字符串
    • 通过ModelAndView对象返回
  • 回写数据
    • 直接返回字符串
    • 返回对象或集合

页面跳转

直接返回字符串

直接返回字符串:此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转。
spring-mvc.xml里的配置(配置内部资源视图解析器)


<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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
        ">
    <context:component-scan base-package="com.liu" >
        
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    context:component-scan>

    
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/views/" />
        <property name="suffix" value=".jsp" />
    bean>

    




    
    <mvc:default-servlet-handler />
beans>

在业务层中

@RequestMapping("/quick")
public String quickMethod(){
	return "index" ;
}

就拼接成了转发资源地址:/views/index.jsp

返回带有前缀的字符串:
转发:forward:/views/index.jsp
重定向:redirect:/index.jsp

返回ModelAndView对象

  • 第一种(自己new一个ModelAndView对象)
@RequestMapping("/quick1")
public ModelAndView quickMethod1(){
    /*
    * Model:模型  作用:封装数据
    * View:视图   作用:展示数据
    * */
    ModelAndView modelAndView =new ModelAndView();
    modelAndView.addObject("username","liu");   //传值变量,index.jsp 页面显示
    // 设置视图名称
    modelAndView.setViewName("index");  //返回 /views/index.jsp 页面
    return modelAndView;
}
  • 第二种(SpringMVC用ModelAndView参数会帮你注入ModelAndView对象)
@RequestMapping("/quick2")
public ModelAndView quickMethod2(ModelAndView modelAndView){
    modelAndView.addObject("username","liu");   //传值变量,index.jsp 页面显示
    // 设置视图名称
    modelAndView.setViewName("index");  //返回 /views/index.jsp 页面
    return modelAndView;
}
  • 第三种(用 Model 对象)
@RequestMapping("/quick3")
public String quickMethod3(Model model){
    model.addAttribute("username","liu");
    return "index";
}

回写数据(异步方式)

直接返回字符串

@RequestMapping("/quick4")
@ResponseBody    //不进行页面跳转(说明:直接回写数据方式返回)
public String quickMethod4(){
    return "不进行页面跳转(说明:直接回写数据方式返回)";
}

返回对象或集合

得先加入解析json字符串的坐标

	
	......

    
    <dependency>
      <groupId>com.fasterxml.jackson.coregroupId>
      <artifactId>jackson-coreartifactId>
      <version>2.9.0version>
    dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.coregroupId>
      <artifactId>jackson-databindartifactId>
      <version>2.9.0version>
    dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.coregroupId>
      <artifactId>jackson-annotationsartifactId>
      <version>2.9.0version>
    dependency>

	......

返回对象

@RequestMapping("/quick4")
@ResponseBody    //不进行页面跳转(说明:直接回写数据方式返回)
public User quickMethod4(){
    User user=new User();
    user.setUsername("liu");
    user.setAge(28);
    return user;
}

返回集合

@RequestMapping("/quick5")
 @ResponseBody    //不进行页面跳转(说明:直接回写数据方式返回)
 public List quickMethod5(){
     User user1=new User();
     user1.setUsername("liu");
     user1.setAge(28);

     User user2=new User();
     user2.setUsername("xiu");
     user2.setAge(22);

     ArrayList arrayList=new ArrayList();
     arrayList.add(user1);
     arrayList.add(user2);
     return arrayList;
 }

异步请求响应

名称:@ResponseBody
类型:方法注解、返回值注解
位置:处理器类中的方法前方
作用:将异步提交数据组织成标准请求参数格式,并赋值给形参
范例:

@RequestMapping("/ajaxReturnString")
@ResponseBody
pubiic string ajaxReturnString(){
	system.out.printIn("controller return string ...");
	return "page.jsp";
)

跨域访问

当通过域名A下的操作访问域名B下的资源时,称为跨域访问

跨域访问的概念

  • 协议
  • 工P地址
  • 端口
  • 域名

@Crossorigin

  • 名称:@Crossorigin
  • 类型:方法注解、类注解
  • 位置:处理器类中的方法上方或类上方
  • 作用:设置当前处理器方法/处理器类中所有方法支持跨域访问
  • 范例:
@RequestMapping("/quick6")
@ResponseBody    //不进行页面跳转(说明:直接回写数据方式返回)
@CrossOrigin    //支持跨域访问
public User quickMethod6(){
    User user=new User();
    user.setUsername("liu");
    user.setAge(28);
    return user;
}

拦截器

拦截器简介

  • 拦截器(Interceptor)是一种动态拦截方法调用的机制
  • 作用:
    1. 在指定的方法调用前后执行预先设定后的的代码
    2. 阻止原始方法的执行
    3. 增强
  • 核心原理:AOP思想
  • 拦截器链:多个拦截器按照一定的顺序,对原始被调用功能进行增强

拦截器VS过滤器

  • 归属不同:Filter属于servlet技术,Interceptor属于SpringMVC技术
  • 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强

自定义拦截器开发

自定义拦截器开发入门

创建 拦截器类

package com.liu.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

    // 前面
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("前置运行-------al");
        return true;  // 为 false 后面都不执行,包括 控制器(controller)也不执行
    }

    // 后面
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("后置运行-------bl");
    }

    // 完成后
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("完成后运行-------cl");
    }
}

spring-mvc.xml里配置拦截器


<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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
        ">
    <context:component-scan base-package="com.liu" >
        
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    context:component-scan>

    





    




    
    <mvc:default-servlet-handler />

    
    <mvc:annotation-driven />

    
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/handleRun"/>	
            <bean class="com.liu.interceptor.MyInterceptor" />	
        mvc:interceptor>
    mvc:interceptors>
beans>

拦截器配置与方法参数

方法参数
package com.liu.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

    // 前面(参数处理,权限校验)
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // HttpServletRequest request:请求
        // HttpServletResponse response:响应
        // Object handler:被拦截方法对象
        System.out.println("前置运行-------a1");
        return true;  // 为 false 后面都不执行,包括 控制器(controller)也不执行
    }

    // 后面(返回数据处理,修改返回的页面)
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // ModelAndView modelAndView: 返回的结果     作用:修改返回的页面
        System.out.println("后置运行-------b1");
    }

    // 完成后(处理异常)
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // Exception ex: 拦截的异常
        System.out.println("完成后运行-------c1");
    }
}
拦截器配置

<mvc:interceptors>
    <mvc:interceptor>
        
        <mvc:mapping path="/*"/>            
        <mvc:mapping path="/handleRun"/>    
        <mvc:mapping path="/handleRun*"/>   

        <mvc:exclude-mapping path="/b*"/>      

        <bean class="com.liu.interceptor.MyInterceptor" />
    mvc:interceptor>
mvc:interceptors>
  • mapping标签:可以配置多个,支持通配符 *
    • *表示任意名称,/*仅表示根路径下任意名称,不再往下匹配目录
    • **表示当前路径及其子路径,/**表示根路径及其子路径下任意名称
  • exclude-mapping标签:用于剔除不符合要求的配置项,加速配置过程,支持通配符*
  • bean标签(ref标签)∶只能配置一个

多拦截器配置


<mvc:interceptors>

    <mvc:interceptor>
        <mvc:mapping path="/*"/> 
        <bean class="com.liu.interceptor.MyInterceptor1" />
    mvc:interceptor>
	
	<mvc:interceptor>
        <mvc:mapping path="/*"/>     
        <bean class="com.liu.interceptor.MyInterceptor2" />
    mvc:interceptor>
    
	<mvc:interceptor>
        <mvc:mapping path="/*"/>
        <bean class="com.liu.interceptor.MyInterceptor3" />
    mvc:interceptor>

mvc:interceptors>

执行顺序为

a1
a2
a3
我是方法
b3
b2
b1
c3
c2
c1

当 a2 为的返回值false时,执行顺序为

a1
a2
c1
拦截器链配置
  • 当配置多个拦截器时,形成拦截器链
  • 拦截器链的运行顺序参照配置的先后顺序
  • 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
  • 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作
责任链模式
  • 责任链模式是一种行为模式
  • 特征:
    • 沿着一条预先设定的任务链l顺序执行,每个节点具有独立的工作任务
  • 优势:
    • 独立性:只关注当前节点的任务,对其他任务直接放行到下一节点
    • 隔离性:具备链式传递特征,无需知晓整体链路结构,只需等待请求到达后进行处理即可
    • 灵活性:可以任意修改链路结构动态新增或删减整体链路责任
    • 解耦:将动态任务与原始任务解耦
  • 弊端:
    • 链路过长时,处理效率低下
    • 可能存在节点上的循环引用现象,造成死循环,导致系统崩溃

异常处理

通用异常处理方案

这个方案是在接受完参数后才工作的,所以接受参数是发生异常无法处理
创建异常处理类
只要继承 HandlerExceptionResolver 接口 和 @Component 报错对跳转到这个

package com.liu.exception;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class ExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        ModelAndView modelAndView=new ModelAndView();

		// 根据异常的种类不同,进行分门别类的管理,返回不同的信息
        if (e instanceof  NullPointerException){
            modelAndView.addObject("msg","空指针异常");
        }else if (e instanceof ArithmeticException){
            modelAndView.addObject("msg","算数运算异常");
        }else {
            modelAndView.addObject("msg","未知的异常");
        }

        modelAndView.setViewName("error.jsp");
        return modelAndView;
    }
}

使用注解实现异常分类管理(推荐用这个)

注解方式工作比较早,在Controller形成前就工作了,所以能处理接受参数时发生异常

  • 名称:@ControllerAdvice
  • 类型:类注解
  • 位置:异常处理器类上方
  • 作用:设置当前类为异常处理器类
  • 范例:
@Component
@ControllerAdvice
public class ExceptionAdvice {}
package com.liu.exception;

import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@Component
@ControllerAdvice
public class ExceptionAdvice {

    @ExceptionHandler(NullPointerException.class)
    @ResponseBody       // 不返回页面
    public String doNullException(Exception ex){
        return "空指针异常------";
    }

    @ExceptionHandler(ArithmeticException.class)
    @ResponseBody       // 不返回页面
    public String doArithmeticException(Exception ex){
        return "算数异常------";
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody       // 不返回页面
    public String doException(Exception ex){
        return "未知异常------";
    }
}

项目异常处理方案

  • 异常分类

    • 业务异常:
      • 规范的用户行为产生的异常
      • 不规范的用户行为操作产生的异常
    • 系统异常:
      • 项目运行过程中可预计且无法避免的异常
    • 其他异常:
      • 编程人员未预期到的异常
  • 异常处理方案

    • 业务异常:
      • 发送对应消息传递给用户,提醒规范操作
    • 系统异常:
      • 发送固定消息传递给用户,安抚用户
      • 发送特定消息给运维人员,提醒维护
      • 记录日志
    • 其他异常:
      • 发送固定消息传递给用户,安抚用户
      • 发送特定消息给编程人员,提醒维护
        • 口纳入预期范围内
      • 记录日志

实现方案

  • 因为有太多的异常不可能都处理,一个一个写有太麻烦了
  • 所以可以创建 三个自定义异常方案:
用户行为异常类:返回用户相关的异常

创建用户行为异常类BusinessException

package com.liu.exception;

public class BusinessException extends RuntimeException {
    public BusinessException() {
    }

    public BusinessException(String message) {
        super(message);
    }

    public BusinessException(String message, Throwable cause) {
        super(message, cause);
    }

    public BusinessException(Throwable cause) {
        super(cause);
    }

    public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

把用户相关错误行为 都用这个类来接受(相当于中间机制)

if(user.getName().trim( ).length()< 8){
	throw new BusinessException("对不起,用户名长度不满足要求,话重新输入");
}
if(user.getAge() < 0) {
	throw new BusinessException("对不起,年龄必须是o到100之间的数字!");
}
系统异常类:返回用户相关的异常

创建系统异常类SystemException

package com.liu.exception;

public class SystemException extends RuntimeException {
    public SystemException() {
    }

    public SystemException(String message) {
        super(message);
    }

    public SystemException(String message, Throwable cause) {
        super(message, cause);
    }

    public SystemException(Throwable cause) {
        super(cause);
    }

    public SystemException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

在发生系统级错误用于接受,进行统一处理(如:告诉用户系统出错、告诉运维人员就行维护,进行日志写入等)

try {
	//模拟连接数据库连接失败时
    throw new SQLException();
} catch (SQLException e) {
    throw new SystemException("数据库连接超时!",e);
}

项目错误处理类(用于处理接受到的用户行为异常类错误和系统异常类错误)

package com.liu.exception;

import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@Component
@ControllerAdvice
public class ProjectExceptionAdvice {

    @ExceptionHandler(BusinessException.class)
    public String doBusinessException(Exception ex, Model m){
        m.addAttribute("msg",ex.getMessage());
        return "error.jsp";
    }

    @ExceptionHandler(SystemException.class)
    public String doSystemException(Exception ex, Model m){
        m.addAttribute("msg","服务器连接失败请联系管理员!");

        //实际的问题显现更应该传递给redis服务器,运维人员通过后台系统查看

        return "error.jsp";
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody       // 不返回页面
    public String doException(Exception ex, Model m){
        m.addAttribute("msg",ex.getMessage());
        
        // 将ex对象保存起来
        
        return "error.jsp";
    }
}

实用技术

文件上传下载

MultipartResolver接口

  • MultipartResolver接口定义了文件上传过程中的相关操作,并对通用性操作进行了封装
    • MultipartResolver接口底层实现类CommonsMultipartResovler
    • CommonsMultipartResovler并未自主实现文件上传下载对应的功能,而是调用了apache的文件上传下载组件
<dependency>
	<groupId>commons-fileuploadgroupId>
	<artifaotId>commons-fileuploadartifaotId>
	<version>1.4version>
dependency>

实现

(在maven配置文件pom.xml)导入坐标
	......
	
    
    <dependency>
      <groupId>commons-fileuploadgroupId>
      <artifactId>commons-fileuploadartifactId>
      <version>1.4version>
    dependency>
    
	......
(在SpringMVC配置文件spring-mvc.xml)配上文件上传下载接口
    
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="102400000000" />
    bean>
在控制器中

上传文件的input标签中的name名要对应 控制器 接受参数时的变量名

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Titletitle>
head>
<body>
<form action="/fileupload" method="post" enctype="multipart/form-data">
    上传LOGO:<input type="file" name="file" /><br/>
    <input type="submit" value="上传" />
form>
body>
html>
package com.liu.controller;

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

import java.io.File;
import java.io.IOException;

@Controller
public class FileUploadController {
    @RequestMapping("/fileupload")
    public String fileupload(MultipartFile file) throws IOException {
        // 上传文件方法
        file.transferTo(new File("abc.png"));
        return "page.jsp";
    }
}

服务器上传文件注意事项

  • 文件命名问题,获取上传文件名,并解析文件名与扩展名
    file.getoriginalFilename()
  • 文件名过长问题
  • 文件保存路径
ServletContext context = request.getServletContext();
String basePath = context.getRealPath("/uploads");
File file = new File(basePath+"/");
if(!file.exists())file.mkdirs();
  • 重名问题
String uuid = UUID.randomUUID().toString().replace("-","").toUpperCase();

案例:文件路径和多文件上传

package com.liu.controller;

import org.springframework.stereotype.Controller;
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
public class FileUploadController {
    @RequestMapping("/fileupload")
    public String fileupload(MultipartFile file,MultipartFile file1,MultipartFile file2, HttpServletRequest request) throws IOException {

//        System.out.println(file.getSize());             // 文件大小
//        System.out.println(file.getBytes());            // 可以用于写文件
//        System.out.println(file.getContentType());      // 类型
//        System.out.println(file.getName());             // 是 input 的 name
//        System.out.println(file.getOriginalFilename()); // 文件名称
//        System.out.println(file.isEmpty());             // 是否为空

        if (!file.isEmpty()){
            String fileName=file.getOriginalFilename();
            // 设置保存的路径
            String realPath = request.getServletContext().getRealPath("/images");
            file.transferTo(new File(realPath,fileName));
        }
        if (!file1.isEmpty()){
            String fileName=file1.getOriginalFilename();
            // 设置保存的路径
            String realPath = request.getServletContext().getRealPath("/images");
            file1.transferTo(new File(realPath,fileName));
        }
        if (!file2.isEmpty()){
            String fileName=file2.getOriginalFilename();
            // 设置保存的路径
            String realPath = request.getServletContext().getRealPath("/images");
            file2.transferTo(new File(realPath,fileName));
        }
        return "page.jsp";
    }
}

Restful

Rest

  • Rest (REpresentational state Transfer)一种网络资源的访问风格,定义了网络资源的访问方式

    • 传统风格访问路径
      • http://localhost/user/get?id=1
      • http://localhost/deleteuser?id=1
    • Rest风格访问路径
      • http://localhost/user/1
  • Restful是按照Rest风格访问网络资源

  • 优点

    • 隐藏资源的访问行为,通过地址无法得知做的是何种操作
    • 书写简化

Rest行为约定方式

  • GET(查询) http://localhost/user/1 GET
  • POST(保存) http://localhost/user POST
  • PUT (更新) http://localhost/user PUT
  • DELETE(删除) http://localhost/user DELETE

注意:上述行为是约定方式,约定不是规范,可以打破,所以称rest风格,而不是Rest规范

Restful开发入门

  • SpringMvc支持Restful

    • 请求路径访问配置发生变化
      • 控制器定义方式发生变化
      • 页面调用方式发生变化
  • Restful规范主要用于前后端分离的项目

package com.liu.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.ResponseBody;

@Controller
public class UserController {
    @RequestMapping("/user/{id}")
    @ResponseBody
    public String restLocation(@PathVariable Integer id){
        System.out.println("我是UserController--------------get:"+id);
        return "page.jsp";
    }
}
  • 简化
package com.liu.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.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

//@Controller
//@ResponseBody
@RestController         //这句相当于上面的合并
@RequestMapping("/user/")
public class UserController {

    @RequestMapping("{id}")
    public String restLocation(@PathVariable Integer id){
        System.out.println("我是UserController--------------get:"+id);
        return "page.jsp";
    }
}
  • 由于Restful入门开发不知道你要操作什么,所以要加上访问行为
    配置web.xml让SpringMVC支持PUT和DELETE请求行为

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
  
  <filter>
    <filter-name>characterEncodingFilterfilter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
    <init-param>
      <param-name>encodingparam-name>
      <param-value>UTF-8param-value>
    init-param>
  filter>
  <filter-mapping>
    <filter-name>characterEncodingFilterfilter-name>
    <url-pattern>/*url-pattern>
  filter-mapping>

  
  <filter>
    <filter-name>hiddenHttpMethodFilterfilter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
  filter>
  <filter-mapping>
    <filter-name>hiddenHttpMethodFilterfilter-name>
    <servlet-name>DispatcherServletservlet-name>
  filter-mapping>
  
  <servlet>
    <servlet-name>DispatcherServletservlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    <init-param>
      <param-name>contextConfigLocationparam-name>
      <param-value>classpath*:spring-mvc.xmlparam-value>
    init-param>
  servlet>
  <servlet-mapping>
    <servlet-name>DispatcherServletservlet-name>
    <url-pattern>/url-pattern>
  servlet-mapping>

web-app>

在控制器里写

package com.liu.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

//@Controller
//@ResponseBody
@RestController         //这句相当于上面的合并
@RequestMapping("/user/")
public class UserController {
//    @RequestMapping(value = "{id}",method = RequestMethod.GET)
    @GetMapping("{id}")     //等于上面的那句话
    public String get(@PathVariable Integer id){
        System.out.println("我是UserController--------------get:"+id);
        return "page.jsp";
    }

//    @RequestMapping(value = "{id}",method = RequestMethod.POST)
    @PostMapping("{id}")     //等于上面的那句话
    public String post(@PathVariable Integer id){
        System.out.println("我是UserController--------------post:"+id);
        return "page.jsp";
    }

//    @RequestMapping(value = "{id}",method = RequestMethod.PUT)
    @PutMapping("{id}")     //等于上面的那句话
    public String put(@PathVariable Integer id){
        System.out.println("我是UserController--------------put:"+id);
        return "page.jsp";
    }

//    @RequestMapping(value = "{id}",method = RequestMethod.DELETE)
    @DeleteMapping("{id}")     //等于上面的那句话
    public String delete(@PathVariable Integer id){
        System.out.println("我是UserController--------------delete:"+id);
        return "page.jsp";
    }
}

postman

一款可以发送Restful风格请求的工具,方便开发调试。首次运行需要联网注册

表单校验

表单校验框架

  • JSR (Java Specification Requests):Java规范提案
    • 303:提供bean属性相关校验规则
  • JCP (Java comnunity Process):Java社区
  • Hibernate框架中包含一套独立的校验框架hibernate-validator
<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-validator</artifactId>
	<version>6.1.0.Final</version>
</dependency>

注意:6版本以上要 tomcat8.5 以上的版本

入门案例

步骤一:加入相关坐标
	......

    
    <dependency>
      <groupId>javax.validationgroupId>
      <artifactId>validation-apiartifactId>
      <version>2.0.1.Finalversion>
    dependency>

    
    <dependency>
      <groupId>org.hibernategroupId>
      <artifactId>hibernate-validatorartifactId>
      <version>6.1.0.Finalversion>
    dependency>

	......
步骤二:在控制器方法参数上加 @Valid 验证注解
package com.liu.controller;

import com.liu.domain.Employee;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.Valid;

@Controller
public class EmployeeController {

    @RequestMapping("/addemployee")
    public String addEmployee(@Valid Employee employee){
        return "success.jsp";
    }
}
步骤三:在实体类里判断验证
package com.liu.domain;

import javax.validation.constraints.NotBlank;

public class Employee {
    @NotBlank(message = "姓名不能为空")
    private String name;

    private Integer age;

	......
}
步骤四:在控制器方法里接收判断并返回给页面
package com.liu.controller;

import com.liu.domain.Employee;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.validation.Valid;
import java.util.List;

@Controller
public class EmployeeController {

    @RequestMapping("/addemployee")
    public String addEmployee(@Valid Employee employee, Errors errors, Model model){
        if (errors.hasErrors()){    // 条件是否成立
            List<FieldError> fieldErrors = errors.getFieldErrors();   // 条件成立所有对象
            for (FieldError error :fieldErrors){
                
//                System.out.println(error.getField());
//                System.out.println(error.getDefaultMessage());
                
                // 封装返回页面
                model.addAttribute(error.getField(),error.getDefaultMessage());
            }
            return "addemployee.jsp";
        }
        return "success.jsp";
    }
}

实际的校验规则

  • 同一个字段有多个约束条件
  • 引用类型字段如何校验
  • 根据业务不同需要调整是否参与校验
校验器
  • 同一个属性可以添加多个校验器
@NotNull(message="请输入您的年龄")
@Max(value=60,message="年龄最大值不允许超过60岁")
@Min(value=18,message="年龄最小值不允许低于18岁")
private Integer age;// 员工年龄
  • 3种判定空校验器的区别
表单数据 @NotNull @NotEmpty @NotBlank
String s=null false false false
String s="" true false false
String s=" " true true false
String s=“Jock” true true true
具体案例
前端页面
<form action="/addemployee" method="post" >
    员工姓名:<input type="text" name="name" value="liu"><span>${name}span><br/>
    员工年龄:<input type="text" name="age" value="24"><span>${age}span><br/>
    省:<input type="text" name="address.provinceName"><span>${requestScope['address.provinceName']}span>
    <input type="submit" value="提交">
form>
实体类

实体类Employee.java

package com.liu.domain;

import com.liu.controller.groups.GroupA;

import javax.validation.Valid;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

public class Employee {
    @NotBlank(message = "姓名不能为空",groups = {GroupA.class})	// groups 分组
    private String name;

    @NotNull(message = "请输入您的年龄",groups = {GroupA.class})
    @Max(value = 60,message = "不能超过60")
    @Min(value = 18,message = "不能小于18")
    private Integer age;

    @Valid  // 嵌套校验加上这个,这个对象的校验,在自己里面做
    private Address address;

	......
}

实体类Address.java

package com.liu.domain;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.io.Serializable;

public class Address implements Serializable {
    @NotBlank(message = "请输入省份名称")
    private String ProvinceName;

    @NotBlank(message = "请输入城市名称")
    private String cityName;

    @NotBlank(message = "请输入详细地址")
    private String detail;

    @NotBlank(message = "请输入邮政编码")
    @Size(max = 6,min = 6,message = "邮政编码由6位组成")
    private String zipCode;

	......
}
分组接口
package com.liu.controller.groups;

public interface GroupA {
}
控制器
package com.liu.controller;

import com.liu.controller.groups.GroupA;
import com.liu.domain.Employee;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.validation.Valid;
import java.util.List;

@Controller
public class EmployeeController {

	//@Validated 支持分组
    @RequestMapping("/addemployee")
    public String addEmployee(@Validated({GroupA.class}) Employee employee, Errors errors, Model model){
        if (errors.hasErrors()){    // 条件是否成立
            List<FieldError> fieldErrors = errors.getFieldErrors();   // 条件成立所有对象
            for (FieldError error :fieldErrors){

//                System.out.println(error.getField());
//                System.out.println(error.getDefaultMessage());

                // 封装返回页面
                model.addAttribute(error.getField(),error.getDefaultMessage());
            }
            return "addemployee.jsp";
        }
        return "success.jsp";
    }

	// @Valid 不支持分组
    @RequestMapping("/addemployee2")
    public String addEmployee2(@Valid Employee employee, Errors errors, Model model){
        if (errors.hasErrors()){
            List<FieldError> fieldErrors = errors.getFieldErrors();
            for (FieldError error :fieldErrors){
                model.addAttribute(error.getField(),error.getDefaultMessage());
            }
            return "addemployee.jsp";
        }
        return "success.jsp";
    }
}

你可能感兴趣的:(java,spring,mvc,java)