SpringMVC JSR303数据校验与json支持

一.SpringMVC中使用JSR303进行服务器端验证

1. JSR303数据校验

JSR303是Java为Bean数据合法性校验提供给的标准框架,已经包含在 JavaEE6.0中、JSR303通过在Bean 属性中标注类似 @NotNull @Max 等标准的注解指定校验规则,并通过标准的验证接口对 Bean进行验证

2. 添加相关依赖
<dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.0.7.Final</version>
  </dependency>

2.1 给校验对象的指定属性添加校验规则

public class User {

    private Long userId;

    @NotBlank(message = "用户名不能为空")
    private String userName;

    @NotBlank(message = "密码不能为空")
    private String  password;

    @NotBlank(message = "确认密码不能为空")
    private String  password2;
}

2.2 在请求处理方法中,使用@Validated或@Valid注解要验证的对象,并根据BindingResult判断校验是否通过
另外,验证参数后必须紧跟BindingResult参数,否则spring会在校验不通过时直接抛出异常

 @RequestMapping("/toreg")//注册验证消息
    public String toreg(@Validated User user,BindingResult bindingResult,HttpServletRequest req) {
        if(bindingResult.hasErrors()){
            req.setAttribute("msg","注册失败,验证未通过");
        }
        req.setAttribute("msg","注册成功");
        return "";
    }

注1:@Valid和Validated的区别,随便使用哪个都行
@Valid是使用hibernate validation的时候使用
@Validated 是只用spring Validator校验机制使用

2.3 在JSP页面上通过form标签显示消息

  <form:errors path="*" /> 显示表单所有错误
  <form:errors path="user* /> 显示所有以user为前缀的属性对应的错误
  <form:errors path="username"/> 显示特定表单对象属性的错误
  delimiter:如果一个属性有多个错误,错误信息的分隔符。默认是换行

注1:errors标签要放到form标签中才能显示错误消息
注2:如果使用form:errors标签不显示错误消息,请检查Model中是否已经添加了命令对象,没有是不会显示错误消息的

  @ModelAttribute
    public String reg(Model model) {
        User user = new User();
        model.addAttribute("user",user);
        return "reg";//注册页面
    }

2.4 通过BindingResult和form:errors标签在JSP页面显示非验证消息

public String login(@Valid @ModelAttribute Yh yh, BindingResult bindingResult, Model model){
    bindingResult.rejectValue("yhzh", null, "帐号错误");
    ...
  }

bindingResult.rejectValue("email", "validate.email.empty", "邮箱不能为空"); //这个函数有好几个重载的变体
它们是可以支持国际化的。 比如,上面这个例子表示, 错误的字段(filed)是“email”, errorCode是“validate.email.empty”, 与资源文件对应, 第三个是defaultMessage

3. 如何给同一实体类实现分组校验

在这里插入图片描述
3.1 通过接口定义若干个分组
在这里插入图片描述
3.2 给校验对象的指定属性添加校验规则,并指定校验组
在这里插入图片描述
3.3 在请求处理方法中,使用@Validated标记要验证的对象,并指定校验组

@Validated(value=User.ValidateGroups.login.class) User user

还可以对验证进行分组(@Validated)

User.java:

package com.zking.ssm.model;

import lombok.Data;
import org.springframework.stereotype.Repository;

import javax.validation.constraints.NotBlank;

@Repository
@Data
public class User {
    public static interface ValidateGroups {
        //登陆
        public static interface login {
        }
        //注册
        public static interface reg {
        }
    }
    private Long userId;

    @NotBlank(message = "用户名不能为空",groups = {User.ValidateGroups.login.class,User.ValidateGroups.reg.class})
    private String userName;

    @NotBlank(message = "密码不能为空",groups = {User.ValidateGroups.login.class,User.ValidateGroups.reg.class})
    private String  password;

    @NotBlank(message = "确认密码不能为空",groups = {User.ValidateGroups.reg.class})
    private String  password2;
}

xxxController.java:

package com.zking.ssm.controller;

import com.zking.ssm.model.User;
import org.springframework.http.HttpRequest;
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.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

@Controller
@RequestMapping("/user")
public class UserController {

    @ModelAttribute
    public String reg(Model model) {
        User user = new User();
        model.addAttribute("user",user);
        return "reg";
    }

    @RequestMapping("/tologin")//初始化登陆页面
    public String tologin() {
        return "login";
    }
    @RequestMapping("/toreg")//初始化注册页面
    public String toreg() {
        return "reg";
    }

    @RequestMapping("/toreg1")//注册验证消息
    public String toreg1(@Validated(value = User.ValidateGroups.reg.class) User user,
                        BindingResult bindingResult,HttpServletRequest req) {
        if(bindingResult.hasErrors()){
            req.setAttribute("msg","注册失败,验证未通过");
            return "reg";
        }
        req.setAttribute("msg","注册成功");
        return "login";
    }


    @RequestMapping("/tologin1")//登陆校验
    public String tologin1(@Validated(value=User.ValidateGroups.login.class) User user,
                           BindingResult bindingResult, HttpServletRequest req) {
        if(bindingResult.hasErrors()){
            req.setAttribute("msg","验证失败请重新输入");
            return "login";
        }
        req.setAttribute("msg","登陆成功");
        return "login";
    }
}

登陆页面:
Login.jsp:


<%@ taglib prefix="p" uri="http://www.springframework.org/tags/form" %>
<%--
  Created by IntelliJ IDEA.
  User: zjjt
  Date: 2020/7/2
  Time: 22:50
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>JSR303</title>
    <%@include file="/common/head.jsp"%>
    <style>
        .err{
            color: red;
        }
    </style>
</head>
<body>
    <h1>JSR303登陆<%=System.currentTimeMillis()%></h1>
    <div>
        <c:if test="${msg!=null}">
            ${msg}
            <c:remove var="msg"></c:remove>
        </c:if>
    </div>
    <div>
        <f:form modelAttribute="user" action="${ctx}/user/tologin1" method="post" enctype="multipart/form-data">
            <p>
                <f:errors path="*"></f:errors>
            </p>
            账号:<f:input path="userName" ></f:input><f:errors path="userName" cssClass="err"></f:errors><br>
            密码:<f:password path="password" ></f:password><f:errors path="password" cssClass="err"></f:errors><br>
            <input type="submit" value="登陆">
        </f:form>
    </div>
</body>
</html>

注册页面:
Reg.jsp:

<%--
  Created by IntelliJ IDEA.
  User: zjjt
  Date: 2020/7/2
  Time: 22:50
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>JSR303</title>
    <%@include file="/common/head.jsp"%>
    <style>
        .err{
            color: red;
        }
    </style>
</head>
<body>
    <h1>JSR303注册<%=System.currentTimeMillis()%></h1>
    <div>
        <c:if test="${msg!=null}">
            ${msg}
            <c:remove var="msg"></c:remove>
        </c:if>
    </div>
    <div>
        <f:form modelAttribute="user" action="${ctx}/user/toreg1" method="post" enctype="multipart/form-data">
            <p>
                <f:errors path="*"></f:errors>
            </p>
            账号:<f:input path="userName" autocomplete="off"></f:input><f:errors path="userName" cssClass="err"></f:errors> <br>
            密码:<f:password path="password" autocomplete="off"></f:password><f:errors path="password" cssClass="err" ></f:errors> <br>
            确认密码:<f:password path="password2" autocomplete="off"></f:password><f:errors path="password2" cssClass="err"></f:errors> <br>
            <input type="submit" value="确认">
        </f:form>
    </div>
</body>
</html>
4. 通过分组来指定顺序

@GroupSequence({First.class, Second.class, User.class})

实例结果:
如果输入失败则不会跳页面:
在这里插入图片描述
如果输入成功跳页面:
在这里插入图片描述
5. 其它

   bindingResult.getFieldErrors();

二.Spring mvc如何使用转换json对象

1. 添加jackson相关依赖
<dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-databind</artifactId>
     <version>2.9.3</version>
   </dependency>
   <dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-core</artifactId>
     <version>2.9.3</version>
   </dependency>
   <dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-annotations</artifactId>
     <version>2.9.3</version>
   </dependency>     
2. 在spring-mvc.xml的mvc:annotation-driven标签下添加如下内容
 <!--但是,从spring3.1开始DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter的使用已经过时-->
   <!--spring3.1开始我们应该用RequestMappingHandlerMapping来替换DefaultAnnotationHandlerMapping,-->
   <!--spring3.1开始我们应该用用RequestMappingHandlerAdapter来替换AnnotationMethodHandlerAdapter--> 
   <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="mappingJackson2HttpMessageConverter"/>
            </list>
        </property>
   </bean>
   <bean id="mappingJackson2HttpMessageConverter"
          class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <!--处理中文乱码以及避免IE执行AJAX时,返回JSON出现下载文件-->
        <property name="supportedMediaTypes">
            <list>
                <value>text/html;charset=UTF-8</value>
                <value>text/json;charset=UTF-8</value>
                <value>application/json;charset=UTF-8</value>
            </list>
        </property>
   </bean>
3. 在Util导入JsonData用于转换JSON对象

JsonData:

package com.zking.ssm.util;

import java.io.Serializable;
import java.util.HashMap;

/**
 * 服务器返回给客户端的JSON格式的数据
 *
 */
public class JsonData extends HashMap<String, Object> implements Serializable {

    private static final long serialVersionUID = -8855960778711040221L;

    private static final String CODE_KEY = "code";// 操作代码 0 成功 0 失败
    private static final String MESSAGE_KEY = "message";// 操作消息
    private static final String RESULT_KEY = "result";// 结果集
    private static final String PAGE_KEY = "page";// 页码
    private static final String ROWS_KEY = "rows";// 每页行数/页大小
    private static final String TOTAL_KEY = "total";// 总记录数

    public JsonData() {
        super();
        this.put(CODE_KEY, 0);// 默认操作成功
    }

    public void setCode(Integer code) {
        this.put(CODE_KEY, code);
    }

    public void setMessage(String message) {
        this.put(MESSAGE_KEY, message);
    }

    public void setResult(Object result) {
        this.put(RESULT_KEY, result);
    }

    public void setPage(Integer page) {
        this.put(PAGE_KEY, page);
    }

    public void setRows(Integer rows) {
        this.put(ROWS_KEY, rows);
    }

    public void setTotal(Integer total) {
        this.put(TOTAL_KEY, total);
    }

}
4. 在请求处理方法中添加@ResponseBody注解,将返回结果直接转换成JSON
@GetMapping("/get/{bookId}")
    @ResponseBody
    public JsonData get(@PathVariable Integer bookId) {
       JsonData jsonData = new JsonData();
        Book book = bookService.selectByPrimaryKey(bookId);
        jsonData.setResult(book);
        return jsonData;
    }

注:此请求处理方法返回的已经不是视图了

BookController:

   package com.zking.ssm.controller;

import com.zking.ssm.model.Book;
import com.zking.ssm.service.IBookService;
import com.zking.ssm.util.JsonData;
import com.zking.ssm.util.PageBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@Controller
@RequestMapping("/Book")
public class BookController {

    @Autowired
    private IBookService bookService;

    @RequestMapping("/BookList")
    public String BookList(Book book, HttpServletRequest rsq){
        System.out.println(book.getBookName());
        PageBean pageBean = new PageBean();
        pageBean.setRequest(rsq);
        List<Book> list = bookService.list(book, pageBean);
        rsq.setAttribute("list",list);
        rsq.setAttribute("page",pageBean);
        return "BookList";
    }
    @GetMapping("/get/{bookId}")
    @ResponseBody
    public JsonData get(@PathVariable Integer bookId) {
       JsonData jsonData = new JsonData();
        Book book = bookService.selectByPrimaryKey(bookId);
        jsonData.setResult(book);
        return jsonData;
    }
     @GetMapping("/getlist")
    @ResponseBody
    public JsonData get(Book book,HttpServletRequest req) {
        PageBean pageBean = new PageBean();
        pageBean.setRequest(req);
        JsonData jsonData = new JsonData();
        List<Book> list = bookService.list(book, pageBean);
        jsonData.setResult(list);
        return jsonData;
    }
}

在这里插入图片描述
在这里插入图片描述

5. 解决JSON死循环问题
@JsonIgnore标在Javabean的属性上,作用是在将ResponseBody中的Javabean返回前端过程中,被springmvc自带的jackson转化成json字符串时,忽略这个属性。对序列化也有影响。
public class Xxx {
    private String attr1;
    @JsonIgnore
    private String attr2;
    public void setAttr1(String attr){
        this.attr1 = attr;
    }
    public void setAttr2(String attr){
        this.attr2 = attr;
    }
}
6. 解决JSON格式化问题

@JsonFormat

 **日期格式化**

1:一定要加入依赖,否则不生效:

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

2:在实体类get方法上加入注解:

private Date createTime;
@JsonFormat(pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8")
public Date getCreateTime() {
  return createTime;
}
 
public void setCreateTime(Date createTime) {
  this.createTime = createTime;
}

注:pattern = “yyyy年MM月dd日 HH:mm:ss”,还可以是其他格式

7. 转换时指定属性名

@JsonProperty(“error_code”)

@JsonProperty此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化为name,@JsonProperty(value=“name”)。
import com.fasterxml.jackson.annotation.JsonProperty;

public class Student {

    @JsonProperty(value = "real_name")
    private String realName;

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    @Override
    public String toString() {
        return "Student{" +
                "realName='" + realName + '\'' +
                '}';
    }
}

测试:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) throws JsonProcessingException {
        Student student = new Student();
        student.setRealName("zhangsan");
        System.out.println(new ObjectMapper().writeValueAsString(student));
    }
}

结果:

{"real_name":"zhangsan"}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值