06-第6章:SpringMVC拦截器开发案例_第1页
06-第6章:SpringMVC拦截器开发案例_第2页
06-第6章:SpringMVC拦截器开发案例_第3页
06-第6章:SpringMVC拦截器开发案例_第4页
06-第6章:SpringMVC拦截器开发案例_第5页
已阅读5页,还剩75页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

《SSM开发实战》第6章:SpringMVC拦截器开发案例案例实现技术架构正确的请求与响应在动态WEB应用程序开发时,请求处理与响应结果是应用开发的核心主题,只有在客户端发送了正确的请求后,服务端才可以进行正确的业务处理,以及有效的数据响应过滤保护所有的WEB应用都是运行在公网上,并且可以使用的资源路径也都暴露在外部,这样用户在进行请求访问的时候,如果没有按照WEB应用设计的标准进行数据的传输,那么最终就会导致数据转换处理产生异常,或者更严重的情况下,传输了一些恶意的数据,导致项目的核心数据被泄漏。所以在这样的处理环境下就需要对应用程序进行保护,而在标准JakartaEE设计中可以通过过滤器来实现请求数据验证逻辑的定义基于拦截器实现数据验证由于JakartaEE仅仅提供了技术标准,所以现代的Java项目开发中都会基于Spring开发框架,以方便的实现Bean管理与动态代理设计的支持,针对于WEB开发也提供了SpringMVC框架的支持,但是SpringMVC开发处理之中并不建议使用过滤器的方式来进行拦截,主要的原因在于:SpringMVC是基于DispatcherServlet类实现所有请求的分发处理操作,而过滤器是与DispatcherServlet同级别的WEB应用组件,所以如果直接编写过滤器进行处理,那么将无法使用Spring中的Bean管理机制,更无法准确的找到控制层路径对应的处理类的信息。所以要想在SpringMVC之中实现这样的请求数据验证过滤处理,就只能够通过内置拦截器组件来实现拦截器验证处理逻辑在一个项目之中会存在有大量的控制器,所以也会提供有大量需要进行请求数据验证的访问路径存在,那么此时就需要基于可重用的设计思想,通过合理的面向对象设计,基于拦截器处理机制,实现请求数据验证资源文件实现规则配置为了更加灵活的实现请求数据的验证处理,开发者可以通过perties资源文件来定义指定控制层处理方法的验证规则,而验证规则是在系统中由开发者自行定义的,同时在设计时也需要保留程序的可扩展性。因为不同的应用环境会有不同的应用规则存在,所以在进行设计时就要充分的考虑到各Spring提供了MessageSource接口,可以在Spring容器启动时进行所有配置规则的加载,而在每次进行请求拦截时,基于HandlerMethod对象实例进行规则KEY的拼凑,并通过MessageSource实例进行规则查找,最后使用专属的验证类进行规则的判断,如果用户发送的请求数据满足验证规则的需要,则将请求转发到目标Action,如果不满足数据验证规则,则直接跳转到错误页进行显示。种应用场景以及操作简化性的问题。维护验证规则配置此已经得到了关于数据验证处理的初步实现方案,但是在这个实现方案的背后会存在有另外一个现实的问题,那么就是代码维护。试想一下在一个完整的项目应用之中,会存在大量的Action程序类,每一个Action程序类中都可能包含有若干个控制层处理方法,而如果将每一个控制层方法的验证规则都写在一个perties文件之中,则配置项一定会非常的多,并且在维护时也非常的繁琐,一个基础的CRUD控制器所应有的验证项配置。案例项目与子模块在项目开发中一般都会提供有一些专属的工具模块,以供不同的子模块去使用,考虑到数据验证为一个常用的功能,所以在进行项目构建时可以采用公共子模块的形式定义项目依赖管理标准实现架构在本次的案例讲解中,所有的案例都将保存在“ssm-case”项目之中,读者可以根据子模块的名称找到对应的实现源代码,由于不同开发环境的需要,所以只会在ssm-case项目之中配置Spring的核心依赖,而关于SpringMVC有关的依赖配置会在不同的子模块中进行定义。如果现在开发者希望在项目中使用不同的项目进行代码的管理,那么就需要引入Nexus本地私服进行管理,不同的项目直接打包发布到Nexus私服之中,而后再通过Nexus私服进行依赖库的引入,在本系列的《Java项目构建与代码管理开发实战》中已经详细讲解了此操作的实现,如果未掌握的读者请自行参考,也请有需要的读者自行搭建相关服务环境。perties配置project_group=com.yootk

project_version=1.0.0

project_jdk=17validate-case子模块project(":validate-case"){ //子模块配置

dependencies{ //根据需要进行依赖配置

implementation('org.springframework:spring-web:6.0.0-M3')

implementation('org.springframework:spring-webmvc:6.0.0-M3')

implementation('jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api:2.0.0')

implementation('org.mortbay.jasper:taglibs-standard:10.0.2')

implementation('com.fasterxml.jackson.core:jackson-core:2.13.3')

implementation('com.fasterxml.jackson.core:jackson-databind:2.13.3')

implementation('com.fasterxml.jackson.core:jackson-annotations:2.13.3')

compileOnly('jakarta.servlet.jsp:jakarta.servlet.jsp-api:3.1.0')

compileOnly('jakarta.servlet:jakarta.servlet-api:5.0.0')

implementation(project(':common')) //引入公共子模块

}

}

project(":common"){ //子模块配置

dependencies{ //根据需要进行依赖配置

implementation('org.springframework:spring-web:6.0.0-M3')

implementation('org.springframework:spring-webmvc:6.0.0-M3')

implementation('com.fasterxml.jackson.core:jackson-core:2.13.3')

implementation('com.fasterxml.jackson.core:jackson-databind:2.13.3')

implementation('com.fasterxml.jackson.core:jackson-annotations:2.13.3')

compileOnly('jakarta.servlet:jakarta.servlet-api:5.0.0')

}

}AbstractAction公共控制层抽象父类packagemon.web.action.abs; //程序包名称

publicabstractclassAbstractAction{ //控制层父类

privatestaticfinalDateTimeFormatterLOCAL_DATE_FORMAT=

DateTimeFormatter.ofPattern("yyyy-MM-dd"); //日期转换格式

@InitBinder

publicvoidinitBinder(WebDataBinderbinder){ //绑定转换处理

binder.registerCustomEditor(java.util.Date.class,newPropertyEditorSupport(){

@Override

publicvoidsetAsText(Stringtext)throwsIllegalArgumentException{

LocalDatelocalDate=LocalDate.parse(text,

LOCAL_DATE_FORMAT); //设置本地日期实例

Instantinstant=localDate.atStartOfDay()

.atZone(ZoneId.systemDefault()).toInstant();//创建处理实例

super.setValue(java.util.Date.from(instant)); //字符串与日期转换

}

}); //绑定编辑器

}

}YootkServletpackagemon.web.servlet;

publicclassYootkDispatcherServletextendsDispatcherServlet{ //自定义Servlet

privatebooleanrestSwitch=false; //是否使用REST方式显示

privateObjectMappermapper=newObjectMapper(); //创建Jackson数据映射类

publicYootkDispatcherServlet(WebApplicationContextwebApplicationContext){

super(webApplicationContext); //调用父类构造

}

publicvoidsetRestSwitch(booleanrestSwitch){ //设置REST处理标记

this.restSwitch=restSwitch;

}

@Override

protectedvoidnoHandlerFound(HttpServletRequestrequest,

HttpServletResponseresponse)throwsException{

if(this.restSwitch){ //使用REST风格回应

response.setStatus(HttpStatus.NOT_FOUND.value()); //响应状态

response.setContentType(MediaType.APPLICATION_JSON_VALUE);//响应MIME状态

response.setCharacterEncoding("UTF-8"); //响应编码

Map<String,Object>result=newHashMap<>(); //保存响应结果

result.put("message","请求路径未发现,无法处理请求!");//错误信息

result.put("status",HttpStatus.NOT_FOUND); //错误码

response.getWriter().print(mapper.writeValueAsString(result));//数据响应

}else{ //采用普通跳转模式

response.sendRedirect("/notfound"); //自定义路径

}

}

}视图资源配置packagemon.web.config;

@Configuration

publicclassResourceViewConfig{ //视图资源配置类

@Bean

publicInternalResourceViewResolverresourceViewResolver(){//视图解析

InternalResourceViewResolverresolver=

newInternalResourceViewResolver(); //视图解析

resolver.setPrefix("/WEB-INF/pages"); //定义路径前缀

resolver.setSuffix(".jsp"); //定义资源路径后缀

returnresolver;

}

}SpringApplicationContextConfig配置类packagecom.yootk.validate.context.config;

@Configuration

@ComponentScan("mon.web.config") //Spring扫描包

publicclassSpringApplicationContextConfig{} //Spring上下文配置类ObjectMapper子类packagecom.yootk.validate.mapper;

publicclassCustomObjectMapperextendsObjectMapper{//自定义配置类

publicstaticfinalStringDEFAULT_DATE_FORMAT="yyyy-MM-dd";//日期格式

publicCustomObjectMapper(){

super.setDateFormat(newSimpleDateFormat(DEFAULT_DATE_FORMAT));//日期格式化

super.configure(SerializationFeature.INDENT_OUTPUT,true);//格式化输出

super.setSerializationInclusion(JsonInclude.Include.NON_NULL);//NULL不参与序列化

super.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));//配置时区

}

}SpringWEBContextConfig配置类packagecom.yootk.validate.context.config;

@Configuration//配置类

@EnableWebMvc//启用MVC配置

@ComponentScan("com.yootk.validate.action")//SpringWEB扫描包

publicclassSpringWEBContextConfigimplementsWebMvcConfigurer{//SpringWEB配置

@Override

publicvoidaddResourceHandlers(ResourceHandlerRegistryregistry){

registry.addResourceHandler("/yootk-js/**")

.addResourceLocations("/WEB-INF/static/js/");//资源映射

registry.addResourceHandler("/yootk-css/**")

.addResourceLocations("/WEB-INF/static/css/");//资源映射

registry.addResourceHandler("/yootk-images/**")

.addResourceLocations("/WEB-INF/static/images/");//资源映射

registry.addResourceHandler("/yootk-upload/**")

.addResourceLocations("/WEB-INF/upload/");//上传资源映射

}

@Override

publicvoidconfigureMessageConverters(List<HttpMessageConverter<?>>converters){

MappingJackson2HttpMessageConverterconverter=

newMappingJackson2HttpMessageConverter();//Jackson消息转换器

CustomObjectMapperobjectMapper=newCustomObjectMapper();//对象的映射转换处理配置

converter.setObjectMapper(objectMapper);

converter.setSupportedMediaTypes(List.of(

MediaType.APPLICATION_JSON));//MIME类型

converters.add(converter);//追加转换器

}

}SpringMVC启动配置类packagecom.yootk.validate.web.config;

publicclassStartWEBApplication

extendsAbstractAnnotationConfigDispatcherServletInitializer{

@Override

protectedFrameworkServletcreateDispatcherServlet(

WebApplicationContextservletAppContext){

returnnewYootkDispatcherServlet(servletAppContext);//自定义Servlet处理类

}

@Override

protectedClass<?>[]getRootConfigClasses(){ //Spring配置类

returnnewClass[]{SpringApplicationContextConfig.class};

}

@Override

protectedClass<?>[]getServletConfigClasses(){ //SpringWEB配置类

returnnewClass[]{SpringWEBContextConfig.class};

}

@Override

protectedString[]getServletMappings(){ //DispatcherServlet映射路径

returnnewString[]{"/"};

}

@Override

protectedFilter[]getServletFilters(){ //过滤器

CharacterEncodingFiltercharacterEncodingFilter=

newCharacterEncodingFilter(); //编码过滤

characterEncodingFilter.setEncoding("UTF-8"); //编码设置

characterEncodingFilter.setForceEncoding(true); //强制编码

returnnewFilter[]{characterEncodingFilter};

}

@Override

protectedvoidcustomizeRegistration(ServletRegistration.Dynamicregistration){

longmaxFileSize=2097152; //单个文件最大长度(2M)

longmaxRequestSize=5242880; //整体请求文件最大长度(5M)

intfileSizeThreshold=1048576; //文件写入磁盘大小的阈值(1M)

MultipartConfigElementelement=newMultipartConfigElement(

"/tmp",maxFileSize,maxRequestSize,fileSizeThreshold);

registration.setMultipartConfig(element);

}

}配置WEB模块目录数据接收问题在WEB开发中,最为常用的参数传递模式,是通过地址重写或者是表单提交的方式进行传输,此时就可以直接依靠HttpServletRequest接口提供的getParameterValue()以及getParameterValues()方法实现请求数据的接收,但是如果此时用户传递的是一个JSON数据内容,就需要考虑到数据接收问题了请求接收如果此时要通过拦截器进行请求数据的验证,则必然要使用HttpServletRequest接口提供的getInputStream()方法进行请求主体数据的接收,这样才可以进行数据验证的处理,然而该数据流在整个的一次请求之中只允许读取一次。这样当数据验证通过后,SpringMVC的内部会使用Jackson实现JSON请求数据与对象实例(方法参数上使用@RequestBody注解)进行转换,所以此时会再次调用getInputStream()方法,所以最终导致的问题就是Jackson处理时无法接收到所需的数据,也就自然无法实现JSON对象的转换处理。自定义请求封装类JakartaEE为了解决这一设计问题,提供了HttpServletRequestWrapper包装类,开发者可以通过该类扩展一个自定义的请求处理类,并将用户所发送的主体数据直接保存在该类中,这样只要在后续的请求中传递自定义请求类的对象,就可以实现getInputStream()方法的重复调用输入流数据读取的工具类packagemon.http.util;

publicclassReadRequestBodyData{ //读取主体数据

privateReadRequestBodyData(){}

publicstaticbyte[]getRequestBodyData(HttpServletRequestrequest)

throwsIOException{ //输入流数据读取

HttpServletRequestWrapperrequestWrapper=newHttpServletRequestWrapper(request);

intcontentLength=requestWrapper.getContentLength();//获取数据长度

if(contentLength<0){ //长度小于0

returnnull; //返回空数据

}

bytebuffer[]=newbyte[contentLength]; //开辟数组

intlen=0; //读取长度

requestWrapper.getInputStream().read(buffer); //数据读取

returnbuffer;

}

}HttpRequestWraper子类packagemon.http;

publicclassYootkRequestWrapperextendsHttpServletRequestWrapper{//请求包装类

privatebytebody[]; //用户请求数据

publicYootkRequestWrapper(HttpServletRequestrequest){//request包装

super(request);

try{

this.body=ReadRequestBodyData.getRequestBodyData(request);//数据读取

}catch(IOExceptione){}

}

@Override

publicServletInputStreamgetInputStream()throwsIOException{//返回输入流

finalByteArrayInputStreaminputStream=newByteArrayInputStream(body);

returnnewServletInputStream(){

privateinttemp=0;

@Override

publicintread()throwsIOException{ //数据读取

temp=inputStream.read(); //数据读取

returntemp; //数据返回

}

@Override

publicbooleanisFinished(){ //完成判断

returntemp!=1;

}

@Override

publicbooleanisReady(){ //是否准备完毕

returntrue;

}

@Override

publicvoidsetReadListener(ReadListenerreadListener){}

};

}

}YootkStreamFilter过滤器packagemon.http.filter;

publicclassYootkStreamFilterimplementsFilter{ //请求包装过滤

@Override

publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,

FilterChainchain)throwsIOException,ServletException{

HttpServletRequesthttpServletRequest=(HttpServletRequest)request;

if(httpServletRequest.getContentType()!=null){ //判断请求类型

if(httpServletRequest.getContentType()

.startsWith("application/json")){ //MIME类型判断

ServletRequestrequestWrapper=

newYootkRequestWrapper(httpServletRequest);//请求包装

chain.doFilter(requestWrapper,response); //请求转发

}else{

chain.doFilter(request,response); //请求转发

}

}else{

chain.doFilter(request,response); //请求转发

}

}

}StartWEBApplication配置@Override

protectedFilter[]getServletFilters(){ //过滤器

CharacterEncodingFiltercharacterEncodingFilter=

newCharacterEncodingFilter(); //编码过滤

characterEncodingFilter.setEncoding("UTF-8"); //编码设置

characterEncodingFilter.setForceEncoding(true); //强制编码

YootkStreamFilterstreamFilter=newYootkStreamFilter();//请求包装过滤

returnnewFilter[]{characterEncodingFilter,streamFilter};

}拦截规则配置数据验证规则是实现拦截器验证处理的核心关键,在大部分的项目中都可能会包含有数字、日期、日期时间、布尔、数组等相关的验证需要,同时还需要考虑不同的应用场景所带来的一些特殊的验证规则配置,为了解决该类的设计问题,可以在项目中定义一个IValidateRule验证规则接口,而后不同的数据验证处理只需要实现该接口即可数据验证规则No.规则标记规则处理类描述01stringmon.validate.rule.StringValidateRule请求数据不允许为空02intmon.validate.rule.IntValidateRule请求数据必须为整型数据03longmon.validate.rule.LongValidateRule请求数据必须为长整型数据04doublemon.validate.rule.DoubleValidateRule请求数据必须为浮点型数据05booleanmon.validate.rule.BooleanValidateRule请求数据必须为布尔型数据06datemon.validate.rule.DateValidateRule请求数据必须为日期格式数据07datetimemon.validate.rule.DatetimeValidateRule请求数据必须为日期时间格式数据08randmon.validate.rule.RandValidateRule请求数据需要与生成的验证码相匹配09int[]mon.validate.rule.IntsValidateRule请求数组中的每一项必须为整型数据10long[]mon.validate.rule.LongsValidateRule请求数组中的每一项必须为长整型数据11string[]mon.validate.rule.StringsValidateRule请求数组不允许为空IValidateRule数据验证接口packagemon.validate;

publicinterfaceIValidateRule{ //定义数据验证接口

publicbooleanvalidate(Objectstr); //数据验证方法

publicStringerrorMessage(); //返回错误信息

publicdefaultStringgetParameterValue(Objectparam){ //接收参数

if(StringUtils.hasLength(request().getContentType())){

if(request().getContentType().startsWith(MediaType.APPLICATION_JSON_VALUE)){

if(paraminstanceofList){ //是否为List集合

List<String>all=(List)param; //对象转型

returnall.get(0); //返回原始数据

}

returnparam.toString(); //返回原始数据

}

}

returnrequest().getParameter(param.toString()); //接收请求参数

}

publicdefaultString[]getParameterValues(Objectparam){//接收数组

if(StringUtils.hasLength(request().getContentType())){

if(request().getContentType().startsWith(MediaType.APPLICATION_JSON_VALUE)){

if(paraminstanceofList){ //是否为List集合

List<String>all=(List)param; //对象转型

returnall.toArray(newString[]{}); //返回数组

}

}

}

returnrequest().getParameterValues(param.toString());//接收请求参数

}

publicdefaultHttpServletRequestrequest(){

HttpServletRequestrequest=((ServletRequestAttributes)RequestContextHolder

.getRequestAttributes()).getRequest();

returnrequest;

}

}AbstractValidateRule抽象类packagemon.validate.rule.abs;

publicabstractclassAbstractValidateRuleimplementsIValidateRule{

@Override

publicStringerrorMessage(){ //配置公共错误数据

return"请求数据错误,无法通过验证,请确认数据内容是否正确!";

}

}创建字符串数据验证子类packagemon.validate.rule;

publicclassStringValidateRuleextendsAbstractValidateRuleimplementsIValidateRule{

@Override

publicbooleanvalidate(Objectparam){

Stringvalue=getParameterValue(param); //获取请求参数

//StringUtils为Spring内置的字符串处理工具类,直接通过该类方法实现字符串是否为空的判断

returnStringUtils.hasLength(value); //判断数据是否为空

}

@Override

publicStringerrorMessage(){

return"请求数据不允许为空!";

}

}布尔型数据验证子类packagemon.validate.rule;

publicclassBooleanValidateRuleextendsAbstractValidateRuleimplementsIValidateRule{

@Override

publicbooleanvalidate(Objectparam){

Stringvalue=getParameterValue(param); //获取请求参数

if(!StringUtils.hasLength(value)){ //字符串为空

returnfalse; //验证失败

}

if("on".equalsIgnoreCase(value)||"1".equalsIgnoreCase(value)||

"up".equalsIgnoreCase(value)||"yes".equalsIgnoreCase(value)||

"true".equalsIgnoreCase(value)){ //数据判断

returntrue;

}

returnfalse;

}

@Override

publicStringerrorMessage(){

return"请求数据必须是“true”或者是“false”!";

}

}整型数据验证子类packagemon.validate.rule;

publicclassIntValidateRuleextendsAbstractValidateRuleimplementsIValidateRule{

@Override

publicbooleanvalidate(Objectparam){

Stringvalue=getParameterValue(param); //获取请求参数

if(!StringUtils.hasLength(value)){ //字符串为空

returnfalse; //验证失败

}

returnvalue.matches("\\d+"); //正则验证

}

@Override

publicStringerrorMessage(){

return"请求数据必须是整数!";

}

}长整型数据验证子类packagemon.validate.rule;

publicclassLongValidateRuleextendsIntValidateRuleimplementsIValidateRule{}浮点型数据验证子类packagemon.validate.rule;

publicclassDoubleValidateRuleextendsAbstractValidateRuleimplementsIValidateRule{

@Override

publicbooleanvalidate(Objectparam){

Stringvalue=getParameterValue(param); //获取请求参数

if(!StringUtils.hasLength(value)){ //字符串为空

returnfalse; //验证失败

}

returnvalue.matches("\\d+(\\.\\d+)?"); //正则验证

}

@Override

publicStringerrorMessage(){

return"请求数据必须是小数!";

}

}日期数据验证子类packagemon.validate.rule;

publicclassDateValidateRuleextendsAbstractValidateRuleimplementsIValidateRule{

@Override

publicbooleanvalidate(Objectparam){

Stringvalue=getParameterValue(param); //获取请求参数

if(!StringUtils.hasLength(value)){ //字符串为空

returnfalse; //验证失败

}

returnvalue.matches("\\d{4}-\\d{2}-\\d{2}"); //正则验证

}

@Override

publicStringerrorMessage(){

return"请求数据必须是日期型格式(yyyy-MM-dd)!";

}

}日期时间数据验证子类packagemon.validate.rule;

publicclassDatetimeValidateRuleextendsAbstractValidateRuleimplementsIValidateRule{

@Override

publicbooleanvalidate(Objectparam){

Stringvalue=getParameterValue(param); //获取请求参数

if(!StringUtils.hasLength(value)){ //字符串为空

returnfalse; //验证失败

}

returnvalue.matches("\\d{4}-\\d{2}-\\d{2}\\d{2}:\\d{2}:\\d{2}");//正则验证

}

@Override

publicStringerrorMessage(){

return"请求数据必须是日期时间型格式(yyyy-MM-ddHH:mm:ss)!";

}

}验证码数据验证子类packagemon.validate.rule;

publicclassRandValidateRuleextendsAbstractValidateRuleimplementsIValidateRule{

publicstaticfinalStringRAND_SESSION_NAME="rand";

@Override

publicbooleanvalidate(Objectparam){

Stringvalue=getParameterValue(param); //获取请求参数

if(!StringUtils.hasLength(value)){ //数据不为空

returnfalse; //为空直接返回false

}

Stringrand=(String)request().getSession().getAttribute(RAND_SESSION_NAME);

returnvalue.equalsIgnoreCase(rand); //验证码检查

}

@Override

publicStringerrorMessage(){

return"请求的验证码不正确!";

}

}字符串数组验证子类packagemon.validate.rule;

publicclassStringsValidateRuleextendsAbstractValidateRuleimplementsIValidateRule{

@Override

publicbooleanvalidate(Objectparam){

Stringvalues[]=getParameterValues(param); //获取请求参数

returnvalues!=null; //数组不为空

}

@Override

publicStringerrorMessage(){

return"请求数据不允许为空!";

}

}整型数组验证子类packagemon.validate.rule;

publicclassIntsValidateRuleextendsAbstractValidateRuleimplementsIValidateRule{

@Override

publicbooleanvalidate(Objectparam){

Stringvalues[]=getParameterValues(param); //获取请求参数

if(values==null){ //数据为空

returnfalse; //验证失败

}else{ //数据不为空,验证内部数据项

for(intx=0;x<values.length;x++){ //数组循环

if(!values[x].matches("\\d+")){ //数据错误

returnfalse; //验证失败

}

}

returntrue; //验证成功

}

}

@Override

publicStringerrorMessage(){

return"请求内容必须是数字!"; //错误信息KEY

}

}长整型数组验证子类packagemon.validate.rule;

publicclassLongsValidateRuleextendsIntsValidateRuleimplementsIValidateRule{}定义验证注解完整的WEB应用会提供有大量的控制层处理方法,同时不同的控制层方法也会接收不同的请求参数,这样在进行控制层验证处理时,就需要开发者进行明确的验证规则的配置,而为了验证规则的维护可以通过自定义注解进行配置,在拦截处理时,可以通过HandlerMethod对象获取注解以实现请求数据验证请求数据检查注解packagemon.annotation;

@Target({ElementType.METHOD}) //方法上使用注解

@Retention(RetentionPolicy.RUNTIME) //运行时生效

public@interfaceRequestDataValidate{

booleanrequired()defaulttrue; //启用配置

Stringvalue()default""; //验证规则

}数据验证拦截器packageerceptor;

publicclassRequestDataValidateInterceptorimplementsHandlerInterceptor{//拦截器

privatefinalstaticLoggerLOGGER=

LoggerFactory.getLogger(RequestDataValidateInterceptor.class);

privatebooleanrestSwitch=false; //是否使用REST方式显示

@Override

publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,

Objecthandler)throwsException{ //处理前拦截

if(handlerinstanceofHandlerMethod){ //类型判断

HandlerMethodhandlerMethod=(HandlerMethod)handler;//对象转型

//根据当前调用方法获取方法上配置的@RequestDataValidate注解实例

RequestDataValidatevalidate=

handlerMethod.getMethodAnnotation(RequestDataValidate.class);

if(validate==null){ //不提供验证规则

returntrue; //转发到目标Action

}else{ //验证处理

if(!validate.required()){ //不需要验证

returntrue; //转发到目标Action

}else{ //数据验证

Stringrules=validate.value(); //获取验证规则

if(StringUtils.hasLength(rules)){ //验证规则存在

LOGGER.debug("【{}()】{}",

handlerMethod.getMethod().getName(),rules);}

returntrue; //转发到目标Action

}

}

}

returntrue;

}

publicvoidsetRestSwitch(booleanrestSwitch){ //修改拦截器显式风格

this.restSwitch=restSwitch;

}

}SpringWEBContextConfig配置类@Override

publicvoidaddInterceptors(InterceptorRegistryregistry){ //拦截器注册

RequestDataValidateInterceptorinterceptor=newRequestDataValidateInterceptor();

interceptor.setRestSwitch(false); //拦截器显式风格

registry.addInterceptor(interceptor).addPathPatterns("/pages/**");//拦截路径

}Emp程序类packagecom.yootk.validate.vo;

publicclassEmp{ //定义VO类

privateLongempno; //雇员编号为长整型数据

privateStringename; //雇员姓名为字符串数据

privatejava.util.Datehiredate; //雇佣日期为日期型

privateDoublesal; //基本工资为浮点型数据

privateSet<String>roles; //雇员所拥有的角色//Setter、Getter、无参构造、多参构造方法略...

}EmpAction程序类packagecom.yootk.validate.action;

@Controller //控制器标记

@RequestMapping("/pages/emp/") //映射父路径

publicclassEmpActionextendsAbstractAction{

privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(EmpAction.class);

//控制层add()方法在数据接收时需要进行请求数据验证处理

@PostMapping("add") //子路径

@RequestDataValidate(

"empno:long;ename:string;sal:double;hiredate:date;roles:strings")

publicModelAndViewadd(Empemp){

LOGGER.info("【增加雇员数据】雇员编号:{}、姓名:{}、工资:{}、雇佣日期:{}、角色:{}",

emp.getEmpno(),emp.getEname(),emp.getSal(),

emp.getHiredate(),emp.getRoles());

returnnull;

}

@PostMapping("edit") //子路径

@RequestDataValidate(required=true,

value="empno:long;ename:string;sal:double;hiredate:date;roles:strings")

publicModelAndViewedit(@RequestBodyEmpemp){

LOGGER.info("【更新雇员数据】雇员编号:{}、姓名:{}、工资:{}、雇佣日期:{}、角色:{}",

emp.getEmpno(),emp.getEname(),emp.getSal(),

emp.getHiredate(),emp.getRoles());

returnnull;

}

@GetMapping("get") //子路径

//控制层get()方法在数据接收时虽然定义了验证规则,但是由于required属性为false,不会触发验证操作

@RequestDataValidate(required=false,value="empno:long")

publicModelAndViewget(longempno){

LOGGER.info("【查询雇员信息】雇员编号:{}",empno);

returnnull;

}

@DeleteMapping("delete") //子路径

@RequestDataValidate("ids:longs")

publicModelAndViewdelete(longids[]){

LOGGER.info("【删除雇员信息】雇员编号:{}",Arrays.toString(ids));

returnnull;

}

}curl路径测试执行雇员数据增加操作curl-XPOST-d"empno=7369&ename=smith&sal=2450&hiredate=1979-09-19&roles=news&roles=system&roles=message""http://localhost:8080/pages/emp/add"根据编号查询雇员信息curl-XGET"http://localhost:8080/pages/emp/get?empno=7369"执行雇员数据修改操作curl-XPOST"http://localhost:8080/pages/emp/edit"-H"Content-Type:application/json;charset=utf-8"-d"{\"empno\":\"7369\",\"ename\":\"Smith\",\"hiredate\":\"1969-09-19\",\"sal\":\"800\",\"roles\":[\"news\",\"system\",\"message\"]}"根据编号删除雇员数据curl-XDELETE"http://localhost:8080/pages/emp/delete?ids=7369&ids=7566&ids=7839"数据验证处理在使用@RequestDataValidate注解进行请求拦截规则配置时,所有的规则采用的都是“参数名称:验证类型”的形式传递的,而后多个验证规则之间使用分号“;”分割,这时就可以针对于不同的规则调用IValidateRule接口的实现类进行验证处理。为了程序设计结构的管理,可以在定义一个ValidateUtils工具类,以封装验证操作的处理逻辑ValidateUtils工具类packagemon.util;

publicclassValidateUtils{ //数据验证处理

privatefinalstaticLoggerLOGGER=

LoggerFactory.getLogger(RequestDataValidateInterceptor.class);

privateValidateUtils(){} //禁止生成实例

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论