Java-主流框架—(5)Spring--异步调用

1.异步调用

1.1发送异步请求

<a href="javascript:void(0);" id="testAjax">访问controller</a>
<script type="text/javascript" src="/js/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
    $(function(){
    $("#testAjax").click(function(){ //为id="testAjax"的组件绑定点击事件
        $.ajax({ //发送异步调用
            type:"POST", //请求方式: POST请求
            url:"ajaxController", //请求参数(也就是请求内容)
            data:'ajax message', //请求参数(也就是请求内容)
            dataType:"text", //响应正文类型
            contentType:"application/text", //请求正文的MIME类型
        });
    });
});
</script>

1.2接受异步请求参数

 名称: @RequestBody

 类型: 形参注解

 位置:处理器类中的方法形参前方

 作用:将异步提交数据组织成标准请求参数格式,并赋值给形参

 范例:

//为id="testAjax"的组件绑定点击事件
        $("#testAjax").click(function(){
            //发送异步调用
            $.ajax({
               //请求方式:POST请求
               type:"POST",
               //请求的地址
               url:"ajaxController",
               //请求参数(也就是请求内容)
               data:'ajax message',
               //响应正文类型
               dataType:"text",
               //请求正文的MIME类型
               contentType:"application/text",
            });
        });
@RequestMapping("/ajaxController")
public String ajaxController(@RequestBody String message){
    System.out.println(message);
    return "page.jsp";
}  
  • 注解添加到Pojo参数前方时,封装的异步提交数据按照Pojo的属性格式进行关系映射

  • 注解添加到集合参数前方时,封装的异步提交数据按照集合的存储结构进行关系映射

        //为id="testAjaxPojo"的组件绑定点击事件
        $("#testAjaxPojo").click(function(){
            $.ajax({
               type:"POST",
               url:"ajaxPojoToController",
               data:'{"name":"Jock","age":39}',
               dataType:"text",
               contentType:"application/json",
            });
        });
        //为id="testAjaxList"的组件绑定点击事件
        $("#testAjaxList").click(function(){
            $.ajax({
               type:"POST",
               url:"ajaxListToController",
               data:'[{"name":"Jock","age":39},{"name":"Jockme","age":40}]',
               dataType:"text",
               contentType:"application/json",
            });
        });
@RequestMapping("/ajaxPojoToController")
//如果处理参数是POJO,且页面发送的请求数据格式与POJO中的属性对应,@RequestBody注解可以自动映射对应请求数据到POJO中
//注意:POJO中的属性如果请求数据中没有,属性值为null,POJO中没有的属性如果请求数据中有,不进行映射
public String  ajaxPojoToController(@RequestBody User user){
    System.out.println("controller pojo :"+user);
    return "page.jsp";
}

@RequestMapping("/ajaxListToController")
//如果处理参数是List集合且封装了POJO,且页面发送的数据是JSON格式的对象数组,数据将自动映射到集合参数中
public String  ajaxListToController(@RequestBody List<User> userList){
    System.out.println("controller list :"+userList);
    return "page.jsp";
}

1.3异步请求接收响应数据

方法返回值为String时

        //为id="testAjaxReturnString"的组件绑定点击事件
        $("#testAjaxReturnString").click(function(){
            //发送异步调用
            $.ajax({
               type:"POST",
               url:"ajaxReturnString",
               //回调函数
               success:function(data){
                    //打印返回结果
                    alert(data);
               }
            });
        });
    //使用注解@ResponseBody可以将返回的页面不进行解析,直接返回字符串,该注解可以添加到方法上方或返回值前面
    @RequestMapping("/ajaxReturnString")
//    @ResponseBody
    public @ResponseBody String ajaxReturnString(){
        System.out.println("controller return string ...");
        return "page.jsp";
    }

方法返回值为Pojo时,自动封装数据成json对象数据

        //为id="testAjaxReturnJson"的组件绑定点击事件
        $("#testAjaxReturnJson").click(function(){
            //发送异步调用
            $.ajax({
               type:"POST",
               url:"ajaxReturnJson",
               //回调函数
               success:function(data){
                    alert(data);
                    alert(data['name']+" ,  "+data['age']);
               }
            });
        });
    @RequestMapping("/ajaxReturnJson")
    @ResponseBody
    //基于jackon技术,使用@ResponseBody注解可以将返回的POJO对象转成json格式数据
    public User ajaxReturnJson(){
        System.out.println("controller return json pojo...");
        User user = new User();
        user.setName("Jockme");
        user.setAge(39);
        return user;
    }

方法返回值为List时,自动封装数据成json对象数组数据

//为id="testAjaxReturnJsonList"的组件绑定点击事件
        $("#testAjaxReturnJsonList").click(function(){
            //发送异步调用
            $.ajax({
               type:"POST",
               url:"ajaxReturnJsonList",
               //回调函数
               success:function(data){
                    alert(data);
                    alert(data.length);
                    alert(data[0]["name"]);
                    alert(data[1]["age"]);
               }
            });
        });
@RequestMapping("/ajaxReturnJsonList")
    @ResponseBody
    //基于jackon技术,使用@ResponseBody注解可以将返回的保存POJO对象的集合转成json数组格式数据
    public List ajaxReturnJsonList(){
        System.out.println("controller return json list...");
        User user1 = new User();
        user1.setName("Tom");
        user1.setAge(3);

        User user2 = new User();
        user2.setName("Jerry");
        user2.setAge(5);

        ArrayList al = new ArrayList();
        al.add(user1);
        al.add(user2);

        return al;
    }

2.异步请求-跨域访问

2.1跨域访问介绍

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

  • 跨域访问时,会出现无法访问的现象

 2.2跨域环境搭建

  • 为当前主机添加备用域名

    • 修改windows安装目录中的host文件

    • 格式: ip 域名

  • 动态刷新DNS

    • 命令: ipconfig /displaydns

    • 命令: ipconfig /flushdns

2.3跨域访问支持

 名称: @CrossOrigin

 类型: 方法注解 、 类注解

 位置:处理器类中的方法上方 或 类上方

 作用:设置当前处理器方法/处理器类中所有方法支持跨域访问

 范例:

//为id="testCross"的组件绑定点击事件
        $("#testCross").click(function(){
            //发送异步调用
            $.ajax({
               type:"POST",
               url:"cross",
               //回调函数
               success:function(data){
                   alert("跨域调用信息反馈:"+data['name']+" ,  "+data['age']);
               }
            });
        });
@RequestMapping("/cross")
@ResponseBody
//使用@CrossOrigin开启跨域访问
//标注在处理器方法上方表示该方法支持跨域访问
//标注在处理器类上方表示该处理器类中的所有处理器方法均支持跨域访问
@CrossOrigin
public User cross(HttpServletRequest request){
    System.out.println("controller cross..."+request.getRequestURL());
    User user = new User();
    user.setName("Jockme");
    user.setAge(39);
    return user;
}

       //为id="testCross"的组件绑定点击事件
        $("#testCross").click(function(){
            //发送异步调用
            $.ajax({
               type:"POST",
               url:"http://www.jock.com/cross",
               //回调函数
               success:function(data){
                   alert("跨域调用信息反馈:"+data['name']+" ,  "+data['age']);
               }
            });
        });

此时两边的地址都是www.jock.com/cross

3.拦截器

3.1拦截器概念

请求处理过程解析

 拦截器( Interceptor)是一种动态拦截方法调用的机制

 作用:        

        1.在指定的方法调用前后执行预先设定后的的代码

        2.阻止原始方法的执行

 核心原理: AOP思想

 拦截器链:多个拦截器按照一定的顺序,对原始被调用功能进行增强

  • 拦截器VS过滤器

    •  归属不同: Filter属于Servlet技术, Interceptor属于SpringMVC技术

    •  拦截内容不同: Filter对所有访问进行增强, Interceptor仅针对SpringMVC的访问进行增强

 3.2自定义拦截器开发过程

实现HandlerInterceptor接口

//自定义拦截器需要实现HandleInterceptor接口
public class MyInterceptor implements HandlerInterceptor {
    //处理器运行之前执行
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("前置运行----a1");
        //返回值为false将拦截原始处理器的运行
        //如果配置多拦截器,返回值为false将终止当前拦截器后面配置的拦截器的运行
        return true;
    }

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

    //所有拦截器的后置执行全部结束后,执行该操作
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {
        System.out.println("完成运行----c1");
    }

    //三个方法的运行顺序为    preHandle -> postHandle -> afterCompletion
    //如果preHandle返回值为false,三个方法仅运行preHandle
}

配置拦截器

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/showPage"/>
        <bean class="test.interceptor.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

 注意:配置顺序为先配置执行位置,后配置执行类

3.3拦截器执行流程

 3.4拦截器配置与方法参数

3.4.1前置处理方法

原始方法之前运行

public boolean preHandle(HttpServletRequest request,
                         HttpServletResponse response,
                         Object handler) throws Exception {
    System.out.println("preHandle");
    return true;
}
  • 参数

  •  request:请求对象

  •  response:响应对象

  •  handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装

  • 返回值

  •  返回值为false,被拦截的处理器将不执行

3.4.2后置处理方法

原始方法运行后运行,如果原始方法被拦截,则不执行

public void postHandle(HttpServletRequest request,
                       HttpServletResponse response,
                       Object handler,
                       ModelAndView modelAndView) throws Exception {
    System.out.println("postHandle");
}

 参数

 modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整

3.4.3后置处理方法

拦截器最后执行的方法,无论原始方法是否执行

public void afterCompletion(HttpServletRequest request,
                            HttpServletResponse response,
                            Object handler,
                            Exception ex) throws Exception {
    System.out.println("afterCompletion");
}

 参数

 ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理

3.5拦截器配置顶

<mvc:interceptors>
    <!--开启具体的拦截器的使用,可以配置多个-->
    <mvc:interceptor>
        <!--设置拦截器的拦截路径,支持*通配-->
        <!--/**         表示拦截所有映射-->
        <!--/*          表示拦截所有/开头的映射-->
        <!--/user/*     表示拦截所有/user/开头的映射-->
        <!--/user/add*  表示拦截所有/user/开头,且具体映射名称以add开头的映射-->
        <!--/user/*All  表示拦截所有/user/开头,且具体映射名称以All结尾的映射-->
        <mvc:mapping path="/*"/>
        <mvc:mapping path="/**"/>
        <mvc:mapping path="/handleRun*"/>
        <!--设置拦截排除的路径,配置/**或/*,达到快速配置的目的-->
        <mvc:exclude-mapping path="/b*"/>
        <!--指定具体的拦截器类-->
        <bean class="MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

3.6多拦截器配置

 责任链模式

 责任链模式是一种行为模式

 特征:沿着一条预先设定的任务链顺序执行,每个节点具有独立的工作任务

 优势:

独立性:只关注当前节点的任务,对其他任务直接放行到下一节点

隔离性:具备链式传递特征,无需知晓整体链路结构,只需等待请求到达后进行处理即可

灵活性:可以任意修改链路结构动态新增或删减整体链路责任

解耦:将动态任务与原始任务解耦

 弊端:

链路过长时,处理效率低下

可能存在节点上的循环引用现象,造成死循环,导致系统崩溃

4.异常处理

4.1异常处理器

HandlerExceptionResolver接口(异常处理器)

@Component
public class ExceptionResolver implements HandlerExceptionResolver {
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Object handler,
                                         Exception ex) {
        System.out.println("异常处理器正在执行中");
        ModelAndView modelAndView = new ModelAndView();
        //定义异常现象出现后,反馈给用户查看的信息
        modelAndView.addObject("msg","出错啦! ");
        //定义异常现象出现后,反馈给用户查看的页面
        modelAndView.setViewName("error.jsp");
        return modelAndView;
    }
}

根据异常的种类不同,进行分门别类的管理,返回不同的信息

@Component
public class ExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Object handler,
                                         Exception ex) {
        System.out.println("my exception is running ...."+ex);
        ModelAndView modelAndView = new ModelAndView();
        if( ex instanceof NullPointerException){
            modelAndView.addObject("msg","空指针异常");
        }else if ( ex instanceof  ArithmeticException){
            modelAndView.addObject("msg","算数运算异常");
        }else{
            modelAndView.addObject("msg","未知的异常");
        }
        modelAndView.setViewName("error.jsp");
        return modelAndView;
    }
}

4.2注解开发异常处理器

使用注解实现异常分类管理

 名称: @ControllerAdvice(//声明该类是一个Controller的通知类,声明后该类就会被加载成异常处理器)

 类型: 类注解

 位置:异常处理器类上方

 作用:设置当前类为异常处理器类

 范例:

@Component
@ControllerAdvice
public class ExceptionAdvice {
}  

使用注解实现异常分类管理

 名称: @ExceptionHandler

 类型: 方法注解

 位置:异常处理器类中针对指定异常进行处理的方法上方

 作用:设置指定异常的处理方式

 范例:

 说明:处理器方法可以设定多个

@Component
//使用注解开发异常处理器
//声明该类是一个Controller的通知类,声明后该类就会被加载成异常处理器
@ControllerAdvice
public class ExceptionAdvice {

    //类中定义的方法携带@ExceptionHandler注解的会被作为异常处理器,后面添加实际处理的异常类型
    @ExceptionHandler(NullPointerException.class)
    @ResponseBody
    public String doNullException(Exception ex){
        return "空指针异常";
    }

    @ExceptionHandler(ArithmeticException.class)
    @ResponseBody
    public String doArithmeticException(Exception ex){
        return "ArithmeticException";
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String doException(Exception ex){
        return "all";
    }
}

4.3异常处理解决方案

异常处理方案

  • 业务异常: 发送对应消息传递给用户,提醒规范操作

  • 系统异常:

  •  发送固定消息传递给用户,安抚用户

     发送特定消息给运维人员,提醒维护
  •  记录日志
  • 其他异常:

  •  发送固定消息传递给用户,安抚用户

  •  发送特定消息给编程人员,提醒维护

  •  纳入预期范围内

  •  记录日志

4.4自定义异常

异常定义格式

//自定义异常继承RuntimeException,覆盖父类所有的构造方法
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("对不起,年龄必须是0到100之间的数字!");
        }
        if(user.getAge() > 100){
            throw  new SystemException("服务器连接失败,请尽快检查处理!");
        }

通过自定义异常将所有的异常现象进行分类管理,以统一的格式对外呈现异常消息

@Component
@ControllerAdvice
public class ProjectExceptionAdvice {

    @ExceptionHandler(BusinessException.class)
    public String doBusinessException(Exception ex, Model m){
        //使用参数Model将要保存的数据传递到页面上,功能等同于ModelAndView
        //业务异常出现的消息要发送给用户查看
        m.addAttribute("msg",ex.getMessage());
        return "error.jsp";
    }

    @ExceptionHandler(SystemException.class)
    public String doSystemException(Exception ex, Model m){
        //系统异常出现的消息不要发送给用户查看,发送统一的信息给用户看
        m.addAttribute("msg","服务器出现问题,请联系管理员!");
        //实际的问题现象应该传递给redis服务器,运维人员通过后台系统查看
        //实际的问题显现更应该传递给redis服务器,运维人员通过后台系统查看
        return "error.jsp";
    }

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

}

5.实用技术

5.1文件上传下载

上传文件过程分析

MultipartResolver接口

  • MultipartResolver接口定义了文件上传过程中的相关操作,并对通用性操作进行了封装

  • MultipartResolver接口底层实现类CommonsMultipartResovler

  • CommonsMultipartResovler并未自主实现文件上传下载对应的功能,而是调用了apache的文件上传下载组件

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

文件上传下载实现

  • 页面表单

<form action="/fileupload" method="post" enctype="multipart/form-data">
    上传LOGO: <input type="file" name="file"/><br/>
    <input type="submit" value="上传"/>
</form>

SpringMVC配置

<bean id="multipartResolver"
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>

控制器

@RequestMapping(value = "/fileupload")
public void fileupload(MultipartFile file){
    file.transferTo(new File("file.png"));
}

5.2文件上传注意事项

  1. 文件命名问题, 获取上传文件名,并解析文件名与扩展名

  2. 文件名过长问题

  3. 文件保存路径

  4. 重名问题

@RequestMapping(value = "/fileupload")
//参数中定义MultipartFile参数,用于接收页面提交的type=file类型的表单,要求表单名称与参数名相同
public String fileupload(MultipartFile file,MultipartFile file1,MultipartFile file2, HttpServletRequest request) throws IOException {
    System.out.println("file upload is running ..."+file);
    //        MultipartFile参数中封装了上传的文件的相关信息
    //        System.out.println(file.getSize());
    //        System.out.println(file.getBytes().length);
    //        System.out.println(file.getContentType());
    //        System.out.println(file.getName());
    //        System.out.println(file.getOriginalFilename());
    //        System.out.println(file.isEmpty());
    //首先判断是否是空文件,也就是存储空间占用为0的文件
    if(!file.isEmpty()){
        //如果大小在范围要求内正常处理,否则抛出自定义异常告知用户(未实现)
        //获取原始上传的文件名,可以作为当前文件的真实名称保存到数据库中备用
        String fileName = file.getOriginalFilename();
        //设置保存的路径
        String realPath = request.getServletContext().getRealPath("/images");
        //保存文件的方法,指定保存的位置和文件名即可,通常文件名使用随机生成策略产生,避免文件名冲突问题
        file.transferTo(new File(realPath,file.getOriginalFilename()));
    }
    //测试一次性上传多个文件
    if(!file1.isEmpty()){
        String fileName = file1.getOriginalFilename();
        //可以根据需要,对不同种类的文件做不同的存储路径的区分,修改对应的保存位置即可
        String realPath = request.getServletContext().getRealPath("/images");
        file1.transferTo(new File(realPath,file1.getOriginalFilename()));
    }
    if(!file2.isEmpty()){
        String fileName = file2.getOriginalFilename();
        String realPath = request.getServletContext().getRealPath("/images");
        file2.transferTo(new File(realPath,file2.getOriginalFilename()));
    }
    return "page.jsp";
}

5.4Restful风格配置

5.4.1Rest

5.4.2Rest行为约定方式

 GET(查询) http://localhost/user/1 GET

 POST(保存) http://localhost/user POST

 PUT(更新) http://localhost/user PUT

 DELETE(删除) http://localhost/user DELETE

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

5.4.3Restful开发入门

//设置rest风格的控制器
@RestController
//设置公共访问路径,配合下方访问路径使用
@RequestMapping("/user/")
public class UserController {

    //rest风格访问路径完整书写方式
    @RequestMapping("/user/{id}")
    //使用@PathVariable注解获取路径上配置的具名变量,该配置可以使用多次
    public String restLocation(@PathVariable Integer id){
        System.out.println("restful is running ....");
        return "success.jsp";
    }

    //rest风格访问路径简化书写方式,配合类注解@RequestMapping使用
    @RequestMapping("{id}")
    public String restLocation2(@PathVariable Integer id){
        System.out.println("restful is running ....get:"+id);
        return "success.jsp";
    }

    //接收GET请求配置方式
    @RequestMapping(value = "{id}",method = RequestMethod.GET)
    //接收GET请求简化配置方式
    @GetMapping("{id}")
    public String get(@PathVariable Integer id){
        System.out.println("restful is running ....get:"+id);
        return "success.jsp";
    }

    //接收POST请求配置方式
    @RequestMapping(value = "{id}",method = RequestMethod.POST)
    //接收POST请求简化配置方式
    @PostMapping("{id}")
    public String post(@PathVariable Integer id){
        System.out.println("restful is running ....post:"+id);
        return "success.jsp";
    }

    //接收PUT请求简化配置方式
    @RequestMapping(value = "{id}",method = RequestMethod.PUT)
    //接收PUT请求简化配置方式
    @PutMapping("{id}")
    public String put(@PathVariable Integer id){
        System.out.println("restful is running ....put:"+id);
        return "success.jsp";
    }

    //接收DELETE请求简化配置方式
    @RequestMapping(value = "{id}",method = RequestMethod.DELETE)
    //接收DELETE请求简化配置方式
    @DeleteMapping("{id}")
    public String delete(@PathVariable Integer id){
        System.out.println("restful is running ....delete:"+id);
        return "success.jsp";
    }
}
<!--配置拦截器,解析请求中的参数_method,否则无法发起PUT请求与DELETE请求,配合页面表单使用-->
<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <servlet-name>DispatcherServlet</servlet-name>
</filter-mapping>

 开启SpringMVC对Restful风格的访问支持过滤器,即可通过页面表单提交PUT与DELETE请求

 页面表单使用隐藏域提交请求类型,参数名称固定为_method,必须配合提交类型method=post使用

<form action="/user/1" method="post">
    <input type="hidden" name="_method" value="PUT"/>
    <input type="submit"/>
</form>  

Restful请求路径简化配置方式

@RestController
public class UserController {
    @RequestMapping(value = "/user/{id}",method = RequestMethod.DELETE)
    public String restDelete(@PathVariable String id){
        System.out.println("restful is running ....delete:"+id);
        return "success.jsp";
    }
}  

等同于

@DeleteMapping("{id}")
    public String delete(@PathVariable Integer id){
        System.out.println("restful is running ....delete:"+id);
        return "success.jsp";
    }

5.5postman工具安装与使用

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

 6.表单校验

6.1校验框架入门

6.1.1表单校验的重要性

表单校验保障了数据有效性、安全性

数据可以随意输入,导致错误的结果。后端表单校验的重要性。

6.1.2表单校验分类

  • 6.1.3校验位置:

    • 客户端校验

    • 服务端校验

  • 校验内容与对应方式:

    • 格式校验

      • 客户端:使用Js技术,利用正则表达式校验

      • 服务端:使用校验框架

    • 逻辑校验

      • 客户端:使用ajax发送要校验的数据,在服务端完成逻辑校验,返回校验结果

      • 服务端:接收到完整的请求后,在执行业务操作前,完成逻辑校验

6.1.3表单校验规则

  • 长度:例如用户名长度,评论字符数量

  • 非法字符:例如用户名组成

  • 数据格式:例如Email格式、 IP地址格式

  • 边界值:例如转账金额上限,年龄上下限

  • 重复性:例如用户名是否重复

6.1.4表单校验框架

JSR(Java Specification Requests):Java 规范提案

303:提供bean属性相关校验规则

 

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

注意:

tomcat7 :搭配hibernate-validator版本5...Final

tomcat8.5↑ :搭配hibernate-validator版本6...Final

6.2快速使用

1.开启校验

 名称:@Valid 、 @Validated

 类型:形参注解

 位置:处理器类中的实体类类型的方法形参前方

 作用:设定对当前实体类类型参数进行校验

 范例:

@RequestMapping(value = "/addemployee")
public String addEmployee(@Valid Employee employee) {
    System.out.println(employee);
}

2.设置校验规则

 名称:@NotNull

 类型:属性注解 等

 位置:实体类属性上方

 作用:设定当前属性校验规则

 范例: 每个校验规则所携带的参数不同,根据校验规则进行相应的调整 具体的校验规则查看对应的校验框架进行获取

public class Employee{
    @NotNull(message = "姓名不能为空")
    private String name;//员工姓名
}

3.获取错误信息

@RequestMapping(value = "/addemployee")
public String addEmployee(@Valid Employee employee, Errors errors, Model model){
    System.out.println(employee);
    if(errors.hasErrors()){
        for(FieldError error : errors.getFieldErrors()){
            model.addAttribute(error.getField(),error.getDefaultMessage());
        }
        return "addemployee.jsp";
    }
    return "success.jsp";
}  

通过形参Errors获取校验结果数据,通过Model接口将数据封装后传递到页面显示

<form action="/addemployee" method="post">
    员工姓名:<input type="text" name="name"><span style="color:red">${name}</span><br/>
    员工年龄:<input type="text" name="age"><span style="color:red">${age}</span><br/>
    <input type="submit" value="提交">
</form>

通过形参Errors获取校验结果数据,通过Model接口将数据封装后传递到页面显示页面获取后台封装的校验结果信息

6.3多规则校验

同一个属性可以添加多个校验器

@NotNull(message = "请输入您的年龄")
@Max(value = 60,message = "年龄最大值不允许超过60岁")
@Min(value = 18,message = "年龄最小值不允许低于18岁")
private Integer age;//员工年龄

3种判定空校验器的区别

 6.4嵌套校验

 名称:@Valid

 类型:属性注解

 位置:实体类中的引用类型属性上方

 作用:设定当前应用类型属性中的属性开启校验

 范例:

public class Employee {
    //实体类中的引用类型通过标注@Valid注解,设定开启当前引用类型字段中的属性参与校验
    @Valid
    private Address address;
}

 注意:开启嵌套校验后,被校验对象内部需要添加对应的校验规则

6.5分组校验

  • 同一个模块,根据执行的业务不同,需要校验的属性会有不同

    • 新增用户

    • 修改用户

  • 对不同种类的属性进行分组,在校验时可以指定参与校验的字段所属的组类别

    • 定义组(通用)

    • 为属性设置所属组,可以设置多个

    • 开启组校验

public interface GroupOne {
}
public String addEmployee(@Validated({GroupOne.class}) Employee employee){
}  
@NotEmpty(message = "姓名不能为空",groups = {GroupOne.class})
private String name;//员工姓名

---------------------------------------------------------------------------------------------------------------------------------

内容有部分存在书籍、课堂、网络记录,如有雷同纯属巧合
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值