SpringMVC高级篇

1 springMVC组件开发之拦截器

1.1自定义拦截器类

public class RoleInterceptor implements HandlerInterceptor {  
    /** 
     * 拦截器处理器处理之前会先经过该方法:前置方法 
     * @return 如果返回true,会进入(放行)下一个拦截器(链) 
     */  
    @Override  
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
        System.out.println("前置方法,返回true,进入后面的处理流程,返回false,完成处理,请求结束");  
        return true;  
    }  
  
    @Override  
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {  
        System.out.println("后置方法,处理器完成处理,视图渲染之前调用");  
    }  
  
    @Override  
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {  
        System.out.println("完成方法:视图渲染完成");  
    }  
}  

1.2 配置拦截器

java配置:在springMVCConfig类上配置

package com.wise.tiger.config;  
  
//*************************import******************************//  
iguration  
@ComponentScan(basePackages = "com.wise.tiger.web")  
@EnableWebMvc  
public class WebConfig implements WebMvcConfigurer {  
    // 视图解析器  
    @Bean  
    public InternalResourceViewResolver viewResolver() {  
        var viewResolver = new InternalResourceViewResolver();  
        viewResolver.setPrefix("/WEB-INF/pages/");  
        viewResolver.setSuffix(".jsp");  
        return viewResolver;  
    }  

    @Override  
    public void addInterceptors(InterceptorRegistry registry) {  
        registry.addInterceptor(new RoleInterceptor()).addPathPatterns("/control/**");  
        }  
  
    @Override // 静态资源不被前端过滤器  
    public void addResourceHandlers(ResourceHandlerRegistry registry) {  
        registry.addResourceHandler("/static/**")// 添加静态资源的url-pattern  
                .addResourceLocations("/static/");  
    }  
}  

xml配置:在spring-mvc.xml上配置

<mvc:interceptors>  
        <mvc:interceptor>  
            <mvc:mapping path="/controll/**"/>  
            <bean class="com.wise.bbs.interceptor.RoleInterceptor"/>  
        </mvc:interceptor>  
 </mvc:interceptors>  

在xml配置中,用元素mvc:interceptors配置拦截器,在里面可以配置多个拦截器,path属性告诉拦截器拦截什么请求,它使用一个正则式的匹配。下面介绍下用java代码 配置:

1.3 多个拦截器执行顺序

多个拦截器执行顺序犹如嵌套的if语句。首先讨论preHandler方法返回为true的情况,先建三个角色拦截器,对其进行测试,可以看到结果是这样的 (责任链模式)

preHandle1
       preHandle2
                preHandle3
                         postHadle3
                         postHadle2
                         postHadle1
                 afterCompletion3
       afterCompletion2
afterCompletion1

有些时候前置方法可能返回false,我们将RoleInterceptor2中的前置方法给为false进行测试后得到的结果:

preHandle1
          preHandle2
afterCompletion1

注意:当其中一个preHandle方法返回false后,按配置顺序,后面的preHandle方法都不会执行了,而控制器和后面的postHandle也不会再运行。
 

2 springMVC组件开发之表单校验器

        Spring  提供了对Bean的功能校验,通过注解@Valid标明哪个Bean需要启用注解式的验证。在javax.validation.constrains.*中定义了一系列的JSR 303规范给出的注解:

限制

说明

@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之间

@Email

邮箱类型

@NotEmpty

集合,不为空

@NotBlank

不为空字符串

@Positive

数字,正数

@PositiveOrZero

数字,正数或0

@NegativeOrZero

数字,负数

@NegativeOrZero

数字,负数或0

@PastOrPresent

过去或者现在日期

@FutrueOrPresent

将来或者现在日期

 
为了使用这些注解,假设要完成一个保存雇员表单:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
<!DOCTYPE html>  
<html>  
<head>  
    <title>添加员工</title>  
</head>  
<body>  
    <form action="${pageContext.request.contextPath }/control/emp/save" method="post" >  
            用户名:<input type="text" name="username" placeholder="请输入用户名,最小4位,最大12位" required/>  
            <span></span>  
            <br/>  
            密码:<input type="password" name="password" placeholder="请输入登录密码"/><br/>  
            电子邮箱:<input type="email" name="email" placeholder="请输入电子邮箱"/><br/>  
            员工生日:<input type="date" name="bornDate" /><br/>  
            薪水:<input type="number" name="salary" placeholder="请输入员工薪水" /><br/>  
            联系电话:<input type="text" name="phone" placeholder="请输入员工联系电话"  pattern="^1[358]\d{9}$"/><br/>  
            员工简介:  
        <textarea placeholder="请输入员工简介" name="intro"></textarea>   
        <br/>  
        <input type="submit" value="提交" /> <input type="reset">  
    </form:form>  
</body>  
</html>  
校验规则:
  • 户名,密码,电子邮箱,入职日期不能为空
  • 入职日期格式为yyyy-MM-dd,且只能大于今日
  • 生日日期格式为yyyy-MM-dd,且只能是一个过去日期
  • 邮箱需要符合格式:
  •  简介内容不得多于256个字符
  • 薪水最小值为2000,最大值为5万
  • 联系方式需为正确的手机号码(使用正则表达式匹配)

建立pojo,确定校验规则:

public class Employee {  
    private Integer id;  
    /** 
     * 用户名,不允许为空,最小4位,最大12位 
     */  
    @NotBlank(message = "用户名不能为空")  
    @Size(min = 4,max = 12,message = "{employee.username.valid.size.message}")  
    private String username;  
    /** 
     * 密码:不能为空,最小6位 
     */  
    @NotBlank(message = "密码不能为空")  
    @Size(min = 6,max = 12,message = "密码最低6位")  
    private String password;  
      
    /** 
     * 电子邮箱,不能为空,要满足邮箱基本格式 
     */  
    @NotNull(message = "邮箱不能为空")  
    @Email(message="邮箱必须满足基本格式")  
    private String email;  
    /** 
     * 员工生日,格式为:yyyy-MM-dd 
     * 必须是一个过去的日期 
     */  
    @DateTimeFormat(iso = ISO.DATE)  
    @Past(message = "你不能录用还未出生的员工")  
    private LocalDate bornDate;  
      
    /** 
     * 入职日期,格式为:yyyy-MM-dd 
     * 必须是一个现在或者将来的日期 
     */  
    @DateTimeFormat(iso = ISO.DATE)  
    @FutureOrPresent  
    private LocalDate entryDate = LocalDate.now();  
    /** 
     * 员工联系(手机)电话 
     * 必须符合手机号码格式(正则表达式) 
     */  
    @Pattern(regexp = "^1[358]\\d{9}$",message = "请输入正确的手机号码")  
    private String phone;  
    /** 
     * 员工薪水,最低2000,最高5万 
     */  
    @Min(value = 2000,message="工资不能低于2000,否则麻烦了")  
    @Max(value=50000,message="工资不能大于50000,否则交奢侈税")  
    private float salary;  
      
    /** 
     * 员工简介,最大不超过200 
     */  
    @Size(min = 6,max = 12,message = "员工简介不能超过200字")  
    private String intro;  
  
       //***************setter and getter*************/  
}  

       这样就定义了一个pojo,用于接收表单的信息。字段上面的注解反映了对每一个字段的验证要求,这样就可以加入对应校验,如果没有指定message属性,会生成默认的错误信息。message配置项用来定义当校验失败后的错误信息,这样就能启动Spring的检验规则来校验表单了。

 在post请求接收数据时,用控制器验证表单:

@Controller  
@RequestMapping("/control/emp")  
public class EmployeeController {  
    @RequestMapping("/save")  
    public String save(@Valid Employee emp,BindingResult errors) {  
        if(errors.hasErrors()) {  
            return "emp/emp_save";  
        }  
        return "redirect:./list";  
    }  
}  

    使用了注解@Valid标明这个Bean将会被校验,另外一个类型为BindingResult的参数(或者为Errors)是用于保存校验是否存在错误信息的,也就是当采用JSR 303规范进行校验后,它会将这个错误信息保存到这个参数中,在方法中判断是否有错误信息,如果有错误信息,跳转到填写表单页面告诉用户错误信息。

如何在jsp页面中显示错误信息呢?这时可以使用jsp提供给我们的标签库

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
<span style="background-color: #fafafa; font-family: monospace;"><%@ taglib prefix="form"  uri="http://www.springframework.org/tags/form"%></span>  
<!DOCTYPE html>  
<html>  
<head>  
    <title>添加员工</title>  
</head>  
<body>  
    <form:form action="${pageContext.request.contextPath }/control/emp/save" method="post"  modelAttribute="employee">  
            用户名:<input type="text" name="username" placeholder="请输入用户名,最小4位,最大12位" required/>  
            <span><span style="background-color: #fafafa; font-family: monospace;"><form:errors path="username" cssStyle="color: red"/></span></span>  
            <br/>  
            密码:<input type="password" name="password" placeholder="请输入登录密码"/><br/>  
            电子邮箱:<input type="email" name="email" placeholder="请输入电子邮箱"/><br/>  
            员工生日:<input type="date" name="bornDate" /><br/>  
            薪水:<input type="number" name="salary" placeholder="请输入员工薪水" /><br/>  
            联系电话:<input type="text" name="phone" placeholder="请输入员工联系电话"  pattern="^1[358]\d{9}$"/><br/>  
            员工简介:  
        <textarea placeholder="请输入员工简介" name="intro"></textarea>   
        <br/>  
        <input type="submit" value="提交" /> <input type="reset">  
    </form:form>  
</body>  
</html>  

 看起来似乎非常不错,但是我们的message错误提示信息是硬编码在pojo身上,为了避免其硬编码而实现可配置,我们在src/main/resource下新建messageSource.properties文件:

employee.username.valid.notnull.message=用户名不能为空  
employee.username.valid.size.message=用户名不能少于4位且不能超过12位  

上面简单罗列了两个错误信息配置,其它道理一样,哪怎么应用(读取)指定的错误信息呢?在pojo验证规则之上:

/** 
* 用户名,不允许为空,最小4位,最大12位 
*/  
@NotBlank(message = "{employee.username.valid.notnull.message}")  
@Size(min = 4,max = 12,message = "{employee.username.valid.size.message}")  
private String username;  

 可以采用{}表达式对配置文件的key加以读取其对应的value。其它字段同理,到这里还不能读取指定配置文件,需要告诉spring的检验器加载什么样的配置文件,在springMVCConfig配置类配置:

@Configuration  
@ComponentScan(basePackages = "com.wise.tiger.web")  
@EnableWebMvc  
public class WebConfig implements WebMvcConfigurer{  
    @Bean  
    public InternalResourceViewResolver viewResolver() {  
        var viewResolver = new InternalResourceViewResolver();  
        viewResolver.setPrefix("/WEB-INF/pages/");  
        viewResolver.setSuffix(".jsp");  
        return viewResolver;  
    }  
    @Override //静态资源不被前端过滤器过滤  
    public void addResourceHandlers(ResourceHandlerRegistry registry) {  
        registry.addResourceHandler("/static/**")//添加静态资源的url-pattern  
            .addResourceLocations("/static/");  
    }  
    @Bean  
    public ReloadableResourceBundleMessageSource messageResource() {  
        var messageResource = new ReloadableResourceBundleMessageSource();  
        //如果不指定,默认会去classpath下的messages.properties配置文件  
        messageResource.setBasename("classpath:resourceMessage");  
        return messageResource;  
    }  
    /**  
     * 添加表单校验器  
     */  
    @Override  
    public Validator getValidator() {  
        var validator = new LocalValidatorFactoryBean();  
        validator.setProviderClass(HibernateValidator.class);  
        validator.setValidationMessageSource(messageResource());  
        return validator;  
    }  
}  
 分组校验

1.定义分组:可以采用标识接口来进行分组区分

//分组校验1  
public interface ValidationGroup1 {  
}  
  
//分组校验2  
public interface ValidationGroup2 {  
2.在检验规则上添加分组
/** 
* 用户名,不允许为空,最小4位,最大12位 
*/  
@NotBlank(message = "{employee.username.valid.notnull.message}",groups = ValidationGroup1.class)  
@Size(min = 4,max = 12,message = "{employee.username.valid.size.message}",groups = ValidationGroup2.class)  
private String username;
3.在conroller中指定使用的分组校验
@Controller  
@RequestMapping("/control/emp")  
public class EmployeeController {  
    @RequestMapping("/save")  
    public String save( @Validated(ValidationGroup2.class) @ModelAttribute Employee emp,BindingResult errors,Model model) {  
        if(errors.hasErrors()) {  
            for (var i = 0; i < errors.getErrorCount();i++) {  
                System.out.println(errors.getObjectName() + ":" + errors.getFieldError().getDefaultMessage());  
            }  
            return "emp/emp_save";  
        }  
        return "redirect:./list";  
    }  
}  
有时候除了简单的输入格式、非空性等校验,也需要一定的业务校验,Spring提供了Validator接口来实现校验,它将在进入控制器逻辑之前对参数的合法性进行校验。核心代码如下:
public interface Validator {  
    /** 
     * 判断当前校验器是否用于检验clazz类型的pojo 
     * @param clazz -- pojo类型 
     * @return true 启动校验,false 不校验 
     */  
    @Override  
    public boolean supports(Class<?> clazz) {  
        return false;  
    }  
    /** 
     * 检验pojo的合法性 
     * @param target 请求对象 
     * @param errors 错误信息 
     */  
    @Override  
    public void validate(Object target, Errors errors) {       
    }  
}  

、Validator接口是SpringMvc校验表单的核心接口,它只是一个验证器,在Spring中最终被注册到验证器的列表中,这样就可以提供给各个控制器去定义,然后通过supports方法判定是否会启用验证器去验证数据。对于校验的过程,则是通过validate方法去实现的。

package com.wise.tiger.pojo;  
  
import org.springframework.validation.Errors;  
import org.springframework.validation.Validator;  
  
/** 
 * @Description: 员工校验器 
 * @author: <a href="mailto:1020zhaodan@163.com">Adan</a>  
 * @date: 2019年5月28日  下午7:23:40 
 * @version:1.0-snapshot 
 */  
public class EmployeeValidator implements Validator {  
    /** 
     * 判断当前校验器是否用于检验clazz类型的pojo 
     * @param clazz -- pojo类型 
     * @return true 启动校验,false 不校验 
     */  
    @Override  
    public boolean supports(Class<?> clazz) {  
        //判断验证是否为Employee,如果是则进行校验  
        return Employee.class.equals(clazz);  
    }  
  
    /** 
     * 检验pojo的合法性 
     * @param target 请求对象 
     * @param errors 错误信息 
     */  
    @Override  
    public void validate(Object target, Errors errors) {  
        var employee = (Employee)target;  
        //对employee pojo类中年薪计算规则为薪水 * 16  
        var yearlySalary = employee.getSalary() * 16;  
        //如果年薪小于1,则认为业务错误  
        if(yearlySalary < 1)  
            //加入错误信息  
            errors.rejectValue("yearlySalary", null, "年薪和月薪不匹配,月薪输入错误");  
    }  
}  

 需要将该验证器捆绑到对应的控制器中,Spring MVC提供了注解@InitBinder,通过该注解就可以将验证器和控制器捆绑在一起,这样就能对请求表单进行验证了。

@Controller  
@RequestMapping("/control/emp")  
public class EmployeeController {  
    @InitBinder  
    public void initBinder(DataBinder binder){  
        //数据绑定器加入验证器  
        binder.setValidator(new EmployeeValidator());  
    }  
    @RequestMapping("/save")  
    public String save( @Validated(ValidationGroup2.class) @ModelAttribute Employee emp,BindingResult errors,Model model) {  
        if(errors.hasErrors()) {  
            for (var i = 0; i < errors.getErrorCount();i++) {  
                System.out.println(errors.getObjectName() + ":" + errors.getFieldError().getDefaultMessage());  
            }  
            return "emp/emp_save";  
        }  
        return "redirect:./list";  
    }  
}  

这样就能对比较复杂的逻辑关系进行校验了。

 

3 springMVC组件开发之类型转换器

springMVC自带Converter转换类,定义一个转换器实现Converter类,并在Converter后面写上源类型和目标类型,重写convert方法加上@Component并打开注解开关后会自动生效。

@Component
public class PrivilegeConverter implements Converter<String[], Set<Privilege>> {
    @Override
    public Set<Privilege> convert(String[] source) {
        if(source == null) return null;
        var ret = new HashSet<Privilege>();
        for(String dest : source)
            ret.add(new Privilege(dest.split("\\_")[0],dest.split("\\_")[1]));
        return ret;
    }
}

 

附依赖:

dependencies {  
    compile group: 'org.springframework', name: 'spring-context', version: '5.1.7.RELEASE'  
    compile group: 'org.springframework', name: 'spring-webmvc', version: '5.1.7.RELEASE'  
    compile group: 'org.springframework', name: 'spring-test', version: '5.1.7.RELEASE'  
    providedCompile group: 'javax.servlet.jsp', name: 'javax.servlet.jsp-api', version: '2.3.3'  
    providedCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'  
    compile group: 'taglibs', name: 'standard', version: '1.1.2'  
    compile group: 'javax.servlet', name: 'jstl', version: '1.2'  
    compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'  
    compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'  
    compile group: 'org.mybatis', name: 'mybatis-spring', version: '2.0.1'  
    compile group: 'org.mybatis', name: 'mybatis', version: '3.5.1'  
    compile group: 'com.alibaba', name: 'druid', version: '1.1.16'  
    compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.16'  
    compile group: 'org.springframework', name: 'spring-jdbc', version: '5.1.7.RELEASE'  
    compile group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final'  
    compile group: 'org.hibernate', name: 'hibernate-validator', version: '6.0.16.Final'  
    compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.9'  
}  

 

转载于:https://my.oschina.net/u/4134962/blog/3060855

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
[ 2021年,将Spring全家桶的课程进行Review,确保不再有顺序错乱等问题导致学员看不懂内容,进入2022年,将Spring的课程进行整理,整理为案例精讲的系列课程,并开始逐步增加高阶的Spring Security等内容,课件将逐步进行上传,敬请期待! ]本课程是Spring全家桶案例精讲课程的第二部分Spring MVC,Spring案例精讲课程以真实场景、项目实战为导向,循序渐进,深入浅出的讲解Java网络编程,助力您在技术工作中更进一步。 本课程聚焦Java Spring的Web知识点,主要是关于Spring MVC的应用,包含:表单的增删改查、国际化、过滤器、拦截器、日志Log4j2及slf4j的使用、主题更改网站皮肤及样式、文件上传等的案例讲解,并且最后以一个SSM(Spring+Spring MVC+Mybatis)贯穿前后台的案例作为Spring MVC课程的终奖, 从而使大家快速掌握Spring的基础核心知识,快速上手,为面试、工作等做好充足准备。 由于本课程聚焦于案例,即直接上手操作,对于Spring的原理等不会做过多介绍,希望了解原理等内容的需要通过其他视频或者书籍去了解,建议按照该案例课程一步步做下来,之后再去进一步回顾原理,这样能够促进大家对原理有更好的理解。 【通过Spring全家桶,我们保证你能收获到以下几点】 1、掌握Spring全家桶主要部分的开发、实现2、可以使用Spring MVC、Spring Boot、Spring Cloud及Spring Data进行大部分的Spring开发3、初步了解使用微服务、了解使用Spring进行微服务的设计实现4、奠定扎实的Spring技术,具备了一定的独立开发的能力  【实力讲师】 毕业于清华大学软件学院软件工程专业,曾在Accenture、IBM等知名外企任管理及架构职位,近15年的JavaEE经验,近8年的Spring经验,一直致力于架构、设计、开发及管理工作,在电商、零售、制造业等有丰富的项目实施经验 【本课程适用人群】如果你是一定不要错过!  适合于有JavaEE基础的,如:JSP、JSTL、Java基础等的学习者没有基础的学习者跟着课程可以学习,但是需要补充相关基础知识后,才能很好的参与到相关的工作中。 【Spring全家桶课程共包含如下几门】 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值