码迷,mamicode.com
首页 > 编程语言 > 详细

Spring MVC 学习

时间:2020-01-05 22:19:42      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:resolve   form   rac   filter   json   nat   转换方法   else   信息   

URL请求处理流程:

graph LR id1(URL处理方法映射)-->id2(参数解析) id2-->id3(执行方法) id3-->id4(响应请求)

1. URL处理方法映射

1.1 Controller

页面控制器,内部可以包含处理具体请求的方法(@RequestMapping)。

  • @Controller:返回视图,如jsp或者html文件;
  • @RestController:返回JSON,如字符串,或者数组;

1.2 @RequestMapping

  • 作用:指定url请求的处理方法;
  • 作用范围:
    • 用在Controller类上:指定上级路径;
    • 用在Controller内部的方法上:url请求具体的处理方法;
  • 常用属性:
    • value:url路径,可以多个;
    • method:http方法,一般去get或者post;
  • 其他属性:
    • params:对url参数做限制,如必须(不)包含某个参数,以及参数取值限制等;
    • headers:读请求头做限制;
    • consumes:能处理的类型(media type);
    • produces:返回的类型;

1.3 示例:

  1. url匹配

hello()方法可以匹配的路径有:"/", "/hello", "/index";即在浏览器地址栏输入: http://localhost:8080/ http://localhost:8080/hello http://localhost:8080/index 都会进入到hello方法中处理。

@RestController
public class HelloController {

    @RequestMapping(value = {"/", "/hello", "/index"})
    public String hello() {
        return "hello你好";
    }
}
  1. Controller也可以指定路径

下面hello方法对应的url变为:/hello/index

@RestController
@RequestMapping("/hello")
public class HelloController {

    @RequestMapping("index")
    public String hello() {
        return "hello你好";
    }
}
  1. method示例

当不指定method属性时,方法可以同时处理get和post方法。

@RequestMapping(value = "/hello", method = RequestMethod.GET) 指定只能处理get方法,等于:@GetMapping("/hello")

@RequestMapping(value = "/hello", method = RequestMethod.POST) 指定只能处理post方法,等于:@PostMapping("/hello")

@RestController
public class HelloController {

    @RequestMapping(value = "/hello", method = RequestMethod.POST)
    public String hello() {
        return "hello你好";
    }

}

上述写法,在浏览器中访问localhost:8080/hello会提示出错,因为代码中指定的时post方法,而浏览器直接访问时,使用的时get方法。

HTTP Status 405 – 方法不允许
Type Status Report

消息 Request method ‘GET‘ not supported

描述 请求行中接收的方法由源服务器知道,但目标资源不支持

Apache Tomcat/9.0.30
  1. produces可以解决返回乱码

返回值在浏览器中出现乱码,一般是由于没有对返回内容指定编码,导致SpringMVC使用了默认的ISO编码。如下示例指定了使用utf-8编码。

@RequestMapping(value = "/hello", produces = "text/html;charset=utf-8")
public String hello() {
    return "hello你好";
}

不推荐使用produces解决乱码,因为使用转换器更方便。

2. 参数解析

2.1 基本原理

将请求参数解析成key=value对,然后根据方法中参数类型和名称,进行参数转换和填充。

例如:url请求为http://localhost/user/get?id=1&name=Jim,处理方法为:

  1. get(int id, String name),则参数会一一对应;
  2. get(int id),则只会填充id的值;
  3. get(int id, String name, String email),则email的值为null;
  4. get(int id, int age, String name),则会出错,因为age没有值,会设置为null,但是age又是一个基本类型,无法设置为null。可以将age设置为Integer,则不过抛错;
  5. get(User user),则会调用User的setter方法,id和name会被设置,user的其他属性为null;
  6. get(User user, int id),则user.id和id都会被赋值;

2.2 参数来源:请求头和请求体

get和post方法都可以在请求头(request head,即在url后面的参数)中设置参数,但是只有post方法有请求体(request body,表单提交的数据就在这里);

HTTP/1.1 并未规定get不能有请求体,但一般Web服务器不会处理get方法的请求体。

2.3 参数编码

2.3.1 请求头参数编码

的编码一般不需要关注,浏览器默认是utf-8,tomcat8,9 对url的编码也是utf-8。

@RequestMapping(value = "/hello")
public String hello(String msg) {
    System.out.println("msg: " + msg);
    return "hello你好";
}

当请求:GET http://localhost:8080/hello?msg=123中国时,idea中打印无乱码。

msg: 123中国
2.3.2 请求体参数编码

请求体长什么样?

POST http://localhost:8080/rest-user/add
Content-Type: application/x-www-form-urlencoded

id=1&name=Jim吉姆

上面的id=1&name=Jim就是请求体,也是key=value格式的。注意get方法的请求体会被忽略的。

上述请求,在服务器端会出现乱码。原因是方法体未设置编码时,会被默认设置为iso编码。

// Default character encoding to use when {@code request.getCharacterEncoding} 
// returns {@code null}, according to the Servlet spec.
org.springframework.web.util.WebUtils.DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";

请求体可以通过Content-Type设置编码。

POST http://localhost:8080/rest-user/add
Content-Type: application/x-www-form-urlencoded;charset=utf-8

id=1&name=Jim吉姆

上述设置编码后,服务器端不会产生乱码。

2.3.3 通过过滤器或拦截器编码

如果不想在发送请求时设置编码格式,还可以通过过滤器或者拦截器设置编码。

  • 方法一:过滤器 在web.xml的开头添加如下配置:
<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>
    <init-param>
        <param-name>forceRequestEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <servlet-name>dispatcher</servlet-name>
</filter-mapping>
  • 方法二:拦截器

定义拦截器:

public class HelloInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        request.setCharacterEncoding("utf-8");
        return true;
    }
}

配置拦截器:

<mvc:interceptors>
    <mvc:interceptor>
        <bean class="com.bailiban.mvc.interceptor.HelloInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>

拦截器使用了HttpServletRequest,需要导入依赖:

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

2.4 参数转换

浏览器中传递的传输是字符串,但我们方法中参数的类型却多种多样,它们是如何进行转换的呢?

2.4.1 常见情景

常见的转换SpringMVC已经帮我们处理了。 详见:org.springframework.core.convert.converter.Converter接口的实现类。例如:StringToNumber类实现了字符串到数字类型(int,short,float等)的转换。

2.4.2 String -> 自定义类

如2.1示例5所述,根据参数名和setter方法来转换。这也是SpringMVC处理的,不需要我们手动处理。

2.4.3 自定义转换方法

当我们需要将参数转换为Date类型时,SpringMVC无法处理,需要我们自定义转换方法。

public class StringToDateConverter implements Converter<String, Date> {

    private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

    @Override
    public Date convert(String source) {
        try {
            return format.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }
}

配置转换器:

<bean id="myConversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="com.bailiban.mvc.converter.StringToDateConverter" />
        </set>
    </property>
</bean>

2.5 参数相关注解

  • @RequestParam:用在方法的参数上,可以省略。
  • @RequestBody:获取请求体,用在post方法中,也可以省略,SpringMVC会自动帮我们设置对象属性;
  • @PathVaribale:位置参数,restfull风格url使用。
  • @ModelAttribute:当请求参数不完整时,可以使用它注解的方法。注意,同一Controller下的所有方法在运行前,都会执行其注解的方法,有时候可能并不是你想要的。
2.5.1 @ModelAttribute 使用示例
  • 前端请求:
POST http://localhost:8080/rest-user/add
Accept: text/html;charset=utf-8
Content-Type: application/x-www-form-urlencoded;charset=utf-8

id=1&name=Jim123中国
  • 后端处理:
@PostMapping("add")
public String add(User user) {
    System.out.println(user);
    userList.add(user);
    return user.toString();
}
  • @ModelAttribute 方法:
@ModelAttribute
public User getUser(int id) {
    User user = userList.stream().filter(u -> u.getId().equals(id)).findAny().orElse(null);
    user.setFriends(Arrays.asList("Lily", "Lucy"))
        .setDate(new Date());
    return user;
}
  • 请求结果:
User(id=1, name=Jim123中国, friends=[Lily, Lucy], date=Sat Jan 04 21:00:27 CST 2020)

我们可以看到,user的其他属性也被赋值。而name属性使用的是请求参数设置的值。注意@ModelAttribute 方法在请求映射的方法之前运行。

2.6 前端请求参数设置

2.6.1 基本类型

普通参数只需要前后端参数名称一致即可。

2.6.2 自定义类

如2.1和2.4.2所述,与普通参数无异,只是SpringMVC使用了类的setter方法而已。

2.6.3 集合/类参数
  1. 使用多个同名参数:适用于List, Array, Set;
  2. 使用[](中括号):适用于List, Array(请求体中),Map;
  3. 使用.(点号):对象;
  4. 逗号分隔:适用于List, Array, Set;

示例:

1)包含对象属性

@Data
public class User {

    private Integer id;
    private String name;
    private Set<String> friends;
    private Date date;
    private Account account;
    private Account[] accountList;
}

请求:

POST http://localhost:8080/rest-user/add
Accept: text/html;charset=utf-8
Content-Type: application/x-www-form-urlencoded;charset=utf-8

id=5&name=Tim&friends=lily,kate&account.money=100&accountList[0].money=1&accountList[1].money=2

结果:

User(id=5, name=Tim, friends=[lily, kate], date=null, account=Account(money=100.0), accountList=[Account(money=1.0), Account(money=2.0)])

2)逗号分割

GET http://localhost:8080/hello?msg=1,2,3
Accept: text/html
@RequestMapping(value = "/hello")
public String hello(String[] msg) {
    return String.join("###" , msg);
}

结果:

1###2###3

3)数组下标

POST http://localhost:8080/rest-user/add
Accept: text/html;charset=utf-8
Content-Type: application/x-www-form-urlencoded;charset=utf-8

id=5&name=Tim&friends[0]=lily&friends[1]=kate

3. 方法执行

通过映射找到url处理方法,该方法除了业务逻辑外,还需要考虑以何种方式响应。

4. 响应请求

4.1 返回json格式

简单的字符串可以直接返回,但很多时候,我们直接返回的是对象。此时需要工具帮我们将类转换为json字符串。

只需要加入如下依赖即可,SpringMVC会帮我们接收json格式参数(转换对象),并将对象转换为json返回,甚至会帮我们把字符编码设置为utf-8。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>${jackson-version}</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${jackson-version}</version>
</dependency>

相关源码(AnnotationDrivenBeanDefinitionParser.java):

	jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
					ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
---
    if (jackson2Present) {
		beanDef.getPropertyValues().add("requestBodyAdvice",
				new RootBeanDefinition(JsonViewRequestBodyAdvice.class));
	}
---
	if (jackson2Present) {
		beanDef.getPropertyValues().add("responseBodyAdvice",
				new RootBeanDefinition(JsonViewResponseBodyAdvice.class));
	}
---
    if (jackson2Present || gsonPresent) {
		defaultMediaTypes.put("json", MediaType.APPLICATION_JSON_VALUE);
	}
---
	if (jackson2Present) {
		Class<?> type = MappingJackson2HttpMessageConverter.class;
		RootBeanDefinition jacksonConverterDef = createConverterDefinition(type, source);
		GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source);
		jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef);
		messageConverters.add(jacksonConverterDef);
	}

为了使我们的映射方法能够返回 json,需要:

  • 在类上添加@RestController注解;
  • 或者类上为@Controller注解,然后在方法上添加@ResponseBody注解;

4.2 响应页面

直接返回页面名即可。但一般我们使用了模板引擎时,会向模板文件传递数据,如何传递呢?

为了能够正确找到文件,一般需要如下配置:

   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
       <property name="prefix" value="/WEB-INF/pages/" />
       <property name="suffix" value=".jsp" />
   </bean>

在映射方法中,添加一个ModelMap类型的数据,就可以帮我们向模板文件传递数据了。

示例代码:

@RequestMapping(value = "get")
public String get(int id, ModelMap model) {
    model.addAttribute("user",
            userList.stream().filter(u -> u.getId().equals(id)).findAny().orElse(null));
    return "user";
}

该代码做了什么:

  • 添加参数:ModelMap model;
  • 向model添加属性:model.addAttribute("user", xxx);
  • 返回user对应于web\WEB-INF\pages\user.jsp文件;

user.jsp 中,通过${user.id}${user.name}获取user的id和name值:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<html>
<head>
    <title>Title</title>
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
</head>
<body>

<c:if test="${!empty user}">
    <form action="${pageContext.request.contextPath}/user/update" method="post">
        <div><label>ID:<input name="id" value="${user.id}"></label></div>
        <div><label>Name:<input name="name" value="${user.name}"></label></div>
        <div><input type="submit" value="submit"></div>
    </form>
</c:if>

</body>
</html>

注意,方法中的参数也会默认传给页面。下面方法中,参数user会到页面中。

@RequestMapping(value = "get2")
public String get(User user) {
    int id = user.getId();
    User user1 = userList.stream().filter(u -> u.getId().equals(id)).findAny().orElse(null);
    user.setName(user1.getName());
    return "user";
}

为了正常使用jstl/core标签,需要添加依赖:

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

4.3 重定向

核心:解决参数丢失

重定向会使浏览器再发送一次(不同url)请求,第一次提交的参数会丢失。 解决办法:

使用 RedirectAttributes 参数,并使用 addFlashAttribute 方法保存参数值。

示例:

graph LR id1(login)-- 重定向 -->id2(home)

页面代码:

// login.jsp
    <form action="${pageContext.request.contextPath}/user/login" method="post">
        <label>ID: <input name="id" value=""></label><br>
        <label>Name: <input name="name" value=""></label><br>
        <input type="submit" value="Login">
    </form>
// user.jsp
    <div id="user">
        <label>ID: ${user.id}</label><br>
        <label>Name: ${user.name}</label><br>
    </div>

Controller代码:

    @RequestMapping("login")
    public String login(User user, RedirectAttributes redirectAttributes) {
        System.out.println(user);
        if (user.getId() != null) {
            if (user.getId() != null &&
                (userList.stream().anyMatch(u -> u.getId().equals(user.getId()) &&
                        u.getName().equals(user.getName())))) {
                redirectAttributes.addFlashAttribute(user);
                return "redirect:/user/home";
            }
        }
        return "login";
    }

    @RequestMapping("home")
    public String home(User user) {
        if (user.getId() == null) {
            return "redirect:/user/login";
        }
        return "home";
    }

重点:

  • login(User user, RedirectAttributes redirectAttributes):方法添加RedirectAttributes参数;
  • redirectAttributes.addFlashAttribute(user);:传递参数;
  • return "redirect:/user/home";:重定向到home页面;
  • home(User user):home方法会从redirectAttributes中获取user对象;

注意:完成重定向后,user值会清空。可自行刷新home页面,看看会发生什么!

如果想一直保存user的值,该如何处理呢?后续会在登录模块介绍。

4.4 forward

forward相对简单,因为参数没有丢失。

    @RequestMapping("login1")
    public String login(User user) {
        return "forward:/user/login";
    }

当访问 /user/login1时,会丢给/user/login处理,user参数也会自动传递。

效果跟下面写法是一样的:

    @RequestMapping({"login", "login1"})
    public String login(User user, RedirectAttributes redirectAttributes) {
    // ...
    }

说明:@RequestMapping可以指定多个url映射到相同的方法。

5. 登录处理

通过对用户登录的学习,我们可以进一步看到SpringMVC提供了哪些其他有用的功能。

5.1 @SessionAttributes

4.3重定向的学习中,我们使用了RedirectAttributes参数保存user信息,但是在刷新home页面后,user信息丢失了。

@SessionAttributes 可以保存在整个Session使用的数据,很适合保存登录信息。

使用示例:

  • Controller上使用@SessionAttributes,并通过类型(User.class)指定Session保存的的是用户信息。
@Controller
@RequestMapping("/user")
@SessionAttributes(types = {User.class})
public class UserController {
}
  • login处理中,将user信息保存的model中model.addAttribute(user);
    @RequestMapping({"login", "login2"})
//    public String login(User user, RedirectAttributes redirectAttributes) {
    public String login2(User user, ModelMap model) {
        System.out.println(user);
        if (user.getId() != null) {
            if (user.getId() != null &&
                (userList.stream().anyMatch(u -> u.getId().equals(user.getId()) &&
                        u.getName().equals(user.getName())))) {
//                redirectAttributes.addFlashAttribute(user);
                model.addAttribute(user);
                return "redirect:/user/home";
            }
        }
        return "login";
    }

此时,在home页面就可以正常访问user用户信息,且不会出现刷新丢失的问题。

  • logout中,可以清除登录信息:sessionStatus.setComplete();
    @RequestMapping("logout")
    public String logout(SessionStatus sessionStatus) {
        // 清除session,即清除user对象0                                 
        sessionStatus.setComplete();
        return "redirect:/user/login";
    }

5.2 登录验证

在之前的处理中,我们把登录验证放在方法里面,如home方法通过条件:if (user.getId() == null)来判断是否登录:

    @RequestMapping("home")
    public String home(User user) {
        if (user.getId() == null) {
            return "redirect:/user/login";
        }
        return "home";
    }

但如果所有页面都需要登录只会才能访问,在每个映射方法都添加登录验证是不可取的。可以使用拦截器解决。

创建LoginInterceptor拦截器

public class LoginInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 不拦截 login
        if (request.getRequestURI().contains("/login")) {
            return true;
        }
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        if (user == null || user.getId() == null) {
            // 转发
//            request.getRequestDispatcher("/user/login").forward(request, response);
            // 重定向
            response.sendRedirect("/user/login");
            return false;
        }
        return true;
    }
}

login中设置Session级别的user信息:

login方法中添加HttpSession参数,调用其session.setAttribute("session_user", user);方法添加user参数; 示例:

    @RequestMapping("login")
    public String login2(User user, HttpSession session) {
        if (session.getAttribute("user") != null)
            return "redirect:/user/home";

        if (user.getId() != null &&
                (userList.stream().anyMatch(u -> u.getId().equals(user.getId()) &&
                        u.getName().equals(user.getName())))) {
                session.setAttribute("user", user);
                return "redirect:/user/home";
        }
        return "login";
    }

home页面使用user信息,使用@SessionAttribute("user")

    @RequestMapping("home")
    public String home(@SessionAttribute("user") User user) {
        return "home";
    }

更新user

    @PostMapping("update")
    public String update(User user, HttpSession session) {
        System.out.println(user);
        for (int i=0; i<userList.size(); i++) {
            if (userList.get(i).getId().equals(user.getId())) {
                userList.set(i, user);
            }
        }
        session.setAttribute("user", user);
        return "redirect:/user/home";
    }

6. 参数校验

6.1 使用Annotaion JSR-303标准的验证

导入Hibernate Validator依赖:

    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.1.0.Final</version>
    </dependency>

可使用如下注解对属性进行限制:

限制说明
@Null限制只能为null
@NotNull限制必须不为null
@AssertFalse限制必须为false
@AssertTrue限制必须为true
@DecimalMax(value)限制必须为一个不大于指定值的数字
@DecimalMin(value)限制必须为一个不小于指定值的数字
@Digits(integer,fraction)限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future限制必须是一个将来的日期
@Max(value)限制必须为一个不大于指定值的数字
@Min(value)限制必须为一个不小于指定值的数字
@Past限制必须是一个过去的日期
@Pattern(value)限制必须符合指定的正则表达式
@Size(max,min)限制字符长度必须在min到max之间
@Past验证注解的元素值(日期类型)比当前时间早
@NotEmpty验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

示例代码:

  • User属性添加限制@NotEmpty(message="用户名不能为空!")
public class User {

    private Integer id;
    @NotEmpty(message="用户名不能为空!")
    private String name;
}    
  • 参数校验@Validated User user
    @PostMapping("update")
    public String update(@Validated User user, HttpSession session){
    }

当提交的用户名为空时,会抛异常:

org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.logException Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object ‘user‘ on field ‘name‘: rejected value []; codes [NotEmpty.user.name,NotEmpty.name,NotEmpty.java.lang.String,NotEmpty]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.name,name]; arguments []; default message [name]]; default message [用户名不能为空!]]

关于嵌套校验:属性上添加@Valid注解即可。

6.2 自定义校验器

public class UserValidator implements Validator {
    @Override
    public boolean supports(Class<?> clazz) {
        // 判断是否为User类        
        return User.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        User user = (User) target;
        // 判断name是否为空        
        if (StringUtils.isEmpty(user.getName())) {
            errors.rejectValue("name", "-1", "用户名不能为空!");
        }
    }
}
  • 添加校验器,在UserController中添加如下代码:
    @InitBinder
    public void initBinder(DataBinder binder){
        binder.replaceValidators(new UserValidator());
    }

@InitBinder方法也可以添加到@ControllerAdvice注解的类中,或者设置到<annotation-driven>validator属性中。

  • 使用时,user参数也需要添加@Validated注解

6.3 自定义注解校验器

  • 定义校验器:NameValidator
public class NameValidator implements ConstraintValidator<NameValidation, String> {
    @Override
    public void initialize(NameValidation constraintAnnotation) {

    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (StringUtils.isEmpty(value))
            return false;
        return true;
    }
}
  • 定义校验器注解:NameValidation
@Constraint(validatedBy = NameValidator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface NameValidation {

    public String message() default "名称不合法";
    public Class<?>[] groups() default {};
    public Class<? extends Payload>[] payload() default {};

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
    @interface List {
        NameValidation[] value();
    }
}
  • User.name上添加注解:@NameValidation
public class User {

    private Integer id;
    @NameValidation(message="自定义注解校验器:用户名不能为空!")
    private String name;
}    
  • 使用时,与前面两种方法相同。user参数添加@Validated注解即可。

7. 异常处理

在参数校验中,我们直接抛出了异常。这些异常也可以交给Spring MVC处理。

8. 静态文件访问

9. 文件上传

Spring MVC 学习

标签:resolve   form   rac   filter   json   nat   转换方法   else   信息   

原文地址:https://www.cnblogs.com/cheng18/p/12152957.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!