学做网站需要多少钱,免费版企业邮箱注册,网上备案,微信营销方式有哪些五、SpringMVC其他扩展 1. 异常处理机制
1.1 异常处理概念 开发过程中是不可避免地会出现各种异常情况#xff0c;例如网络连接异常、数据格式异常、空指针异常等等。异常的出现可能导致程序的运行出现问题#xff0c;甚至直接导致程序崩溃。因此#xff0c;在开发过程中例如网络连接异常、数据格式异常、空指针异常等等。异常的出现可能导致程序的运行出现问题甚至直接导致程序崩溃。因此在开发过程中合理处理异常、避免异常产生、以及对异常进行有效的调试是非常重要的。 对于异常的处理一般分为两种方式 编程式异常处理是指在代码中显式地编写处理异常的逻辑。它通常涉及对异常类型的检测及其处理例如使用 try-catch 块来捕获异常然后在 catch 块中编写特定的处理代码或者在 finally 块中执行一些清理操作。在编程式异常处理中开发人员需要显式地进行异常处理异常处理代码混杂在业务代码中导致代码可读性较差。声明式异常处理则是将异常处理的逻辑从具体的业务逻辑中分离出来通过配置等方式进行统一的管理和处理。在声明式异常处理中开发人员只需要为方法或类标注相应的注解如 Throws 或 ExceptionHandler就可以处理特定类型的异常。相较于编程式异常处理声明式异常处理可以使代码更加简介、易于维护和扩展。 站在宏观角度来看待声明式事务处理 整个项目从架构这个层面设计的异常处理的统一机制和规范。 一个项目中会包含很多个模块各个模块需要分工完成。如果张三负责的模块按照 A 方案处理异常李四负责的模块按照 B 方案处理异常...各个模块处理异常的思路、代码、命名细节都不一样那么就会让整个项目非常混乱。 使用声明式异常处理可以统一项目处理异常思路项目更加清晰了。 1.2 声明式异常的好处
使用声明式代替编程式来实现异常处理管理 让异常控制和核心业务解耦二者各自维护结构性更好整个项目层面使用同一套规则来管理异常 整个项目代码风格更加统一、简介便于团队成员之间的彼此协作
1.3 基于注解异常声明异常处理
1声明异常处理控制器类
异常处理控制类统一定义异常处理 handler 方法
/*** projectName: com.atguigu.execptionhandler* * description: 全局异常处理器,内部可以定义异常处理Handler!*/
/*** RestControllerAdvice ControllerAdvice ResponseBody* ControllerAdvice 代表当前类的异常处理controller! */
RestControllerAdvice
public class GlobalExceptionHandler {}
2声明异常处理 handler 方法 异常处理 handler 方法和普通的 handler 方法参数接收和响应都一致。只不过异常处理 handler 方法要映射异常发生对应的异常会调用。普通的 handler 方法要使用 RequestMapping 注解映射路径发生对应的路径调用。 /*** 异常处理handler * ExceptionHandler(HttpMessageNotReadableException.class) * 该注解标记异常处理Handler,并且指定发生异常调用该方法!* * * param e 获取异常对象!* return 返回handler处理结果!*/
ExceptionHandler(HttpMessageNotReadableException.class)
public Object handlerJsonDateException(HttpMessageNotReadableException e){return null;
}/*** 当发生空指针异常会触发此方法!* param e* return*/
ExceptionHandler(NullPointerException.class)
public Object handlerNullException(NullPointerException e){return null;
}/*** 所有异常都会触发此方法!但是如果有具体的异常处理Handler! * 具体异常处理Handler优先级更高!* 例如: 发生NullPointerException异常!* 会触发handlerNullException方法,不会触发handlerException方法!* param e* return*/
ExceptionHandler(Exception.class)
public Object handlerException(Exception e){return null;
}
3配置文件扫描控制器类配置
确保异常处理控制类被扫描 !-- 扫描controller对应的包,将handler加入到ioc--context:component-scan base-packagecom.atguigu.controller,com.atguigu.exceptionhandler /
2. 拦截器使用
2.1 拦截器概念
拦截器和过滤器解决问题
生活中
为了提高乘客效率在乘客进入站台前统一检票 程序中
在程序中使用拦截器在请求到达具体 handler 方法前统一执行检测 拦截器 VS 过滤器
相似点 拦截必须先把请求拦住才能执行后续操作过滤拦截器或过滤存在的意义就是对请求进行统一处理放行对请求执行了必要操作后放请求过去让它访问原本想要访问的资源不同点 工作平台不同 过滤器工作在 Servlet 容器中拦截器工作在 SpringMVC 的基础上拦截的范围 过滤器能够拦截到的最大范围是整个 Web 应用拦截器能够拦截到的最大范围是整个 SpringMVC 负责的请求IOC 容器支持 过滤器想得到 IOC 容器需要调用专门的工具方法是间接的拦截器它自己就在 IOC 容器中所以可以直接从 IOC 容器中装配组件也就是可以直接得到 IOC 容器的支持
选择
功能需要如果用 SpringMVC 的拦截器能够实现就不使用过滤器。 2.2 拦截器使用
1创建拦截器类
public class Process01Interceptor implements HandlerInterceptor {// 在处理请求的目标 handler 方法前执行Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println(request request , response response , handler handler);System.out.println(Process01Interceptor.preHandle);// 返回true放行// 返回false不放行return true;}// 在目标 handler 方法之后handler报错不执行!Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println(request request , response response , handler handler , modelAndView modelAndView);System.out.println(Process01Interceptor.postHandle);}// 渲染视图之后执行(最后),一定执行!Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println(request request , response response , handler handler , ex ex);System.out.println(Process01Interceptor.afterCompletion);}
} 单个拦截器执行顺序
preHandle() 方法目标 handler 方法postHandle() 方法渲染视图返回 json 没有此步骤afterCompletion() 方法
2拦截器配置
springmvc.xml
!-- 配置拦截器--
mvc:interceptors!-- 默认拦截器,拦截所有请求--bean classcom.atguigu.interceptor.Process01Interceptor /
/mvc:interceptors 3配置详解
① 默认拦截全部
!-- 具体配置拦截器可以指定拦截的请求地址 --
mvc:interceptor!-- 精确匹配 --mvc:mapping path/common/request/one/bean classcom.atguigu.mvc.interceptor.Process03Interceptor/
/mvc:interceptor
② 精准配置
!-- 具体配置拦截器可以指定拦截的请求地址 --
mvc:interceptor!-- 精确匹配 --mvc:mapping path/common/request/one/bean classcom.atguigu.mvc.interceptor.Process03Interceptor/
/mvc:interceptormvc:interceptor!-- /*匹配路径中的一层 --mvc:mapping path/common/request/*/bean classcom.atguigu.mvc.interceptor.Process04Interceptor/
/mvc:interceptormvc:interceptor!-- /**匹配路径中的多层 --mvc:mapping path/common/request/**/bean classcom.atguigu.mvc.interceptor.Process05Interceptor/
/mvc:interceptor
③ 排除配置
mvc:interceptor!-- /**匹配路径中的多层 --mvc:mapping path/common/request/**/!-- 使用 mvc:exclude-mapping 标签配置不拦截的地址 --mvc:exclude-mapping path/common/request/two/bbb/bean classcom.atguigu.mvc.interceptor.Process05Interceptor/
/mvc:interceptor ④ 多个拦截器执行顺序
preHandle() 方法SpringMVC 会把所有拦截器收集到一起然后按照配置顺序调用各个 preHandle() 方法。postHandle() 方法SpringMVC 会把所有拦截器收集到一起然后按照配置相反的顺序调用各个 postHandle() 方法。afterCompletion() 方法SpringMVC 会把所有拦截器收集到一起然后按照配置相反的顺序调用各个 afterCompletion() 方法。
2.3 拦截器作用位置图解 2.4 拦截器案例
一个网站有 5、6个资源其中有一个为登录资源两个无需登录即可访问另外三个需要登录后才能访问如果不登录就访问那三个资源需要拦截并且提示登录后访问。
访问资源的请求地址
登录资源/public/resource/login
公共资源1/public/resource/one
公共资源2/public/resource/two
私密资源1/private/resource/one
私密资源2/private/resource/two
私密资源3/private/resource/three
案例实现
1 声明资源类
① PublicController
/*** projectName: com.atguigu.controller* description: 公有资源控制类*/
RestController
RequestMapping(public/resource)
public class PublicController {/*** 模拟登录,将假用户数据存储到session中!*/GetMapping(login)public Object login(HttpSession session){session.setAttribute(user,root);return login success!!;}GetMapping(one)public Object one(){return public one;}GetMapping(two)public Object two(){return public two;}
}
② PrivateController
RestController
RequestMapping(private/resource)
public class PrivateController {GetMapping(one)public Object one(){return private one;}GetMapping(two)public Object two(){return private two;}GetMapping(three)public Object three(){return private two;}}
2声明拦截器类
/*** projectName: com.atguigu.interceptor** description: 登录保护拦截器*/
public class LoginProtectInterceptor implements HandlerInterceptor {/*** 登录保护方法* param request current HTTP request* param response current HTTP response* param handler chosen handler to execute, for type and/or instance evaluation* return* throws Exception*/Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {Object user request.getSession().getAttribute(user);if (user null){response.setContentType(text/html;charsetutf-8);//没有登录response.getWriter().print(请先登录,再访问! a href/public/resource/login点击此处登录/a);//拦截,不到达目标地址return false;}return true;}
}
3配置拦截器类
!-- 配置拦截器--
mvc:interceptorsmvc:interceptormvc:mapping path/private/**/bean classcom.atguigu.interceptor.LoginProtectInterceptor //mvc:interceptor
/mvc:interceptors 3. 参数校验 在Web 应用三层架构体系中表述层负责接收浏览器提交的数据业务逻辑层负责数据的处理。为了能够让业务逻辑层基于正确的数据进行处理我们需要在表述层对数据进行检查将错误的数据隔绝在业务逻辑层之外。 1校验概述
JSR 303 是 Java 为Bean 数据合法性校验提供的标准框架它已经包含在 JavaEE 6.0标准中。JSR 303 通过在 Bean 属性上标注类似于 NoNull、Max 等标准的注解指定校验规则并通过标准的验证接口对 Bean 进行验证。 注解规则Null标注值必须为 nullNotNull标注值不可为 nullAssertTrue标注值必须为 trueAssertFalse标注值必须为 falseMin(value)标注值必须大于或等于 valueMax(value)标注值必须小于或等于 valueDecimalMin(value)标注值必须大于或等于 valueDecimalMax(value)标注值必须小于或等于 valueSize(max,min)标注值大小必须在 max 和 min 限定的范围内Digits(integer,fratction)标注值值必须是一个数字且必须在可接受的范围内Past标注值只能用于日期型且必须是过去的日期Future标注值只能用于日期型且必须是将来的日期Pattern(value)标注值必须符合指定的正则表达式JSR 303 只是一套标准需要提供其实现才可以使用。Hibernate Validator 是 JSR 303 的一个参考实现除支持所有标准的校验注解外它还支持以下的扩展注解注解规则-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Email标注值必须是格式正确的 Email 地址Length标注值字符串大小必须在指定的范围内NotEmpty标注值字符串不能是空字符串Range标注值必须在指定的范围内Spring 4.0 版本已经拥有自己独立的数据校验框架同时支持 JSR 303 标准的校验框架。Spring 在进行数据绑定时可同时调用校验框架完成数据校验工作。在SpringMVC 中可直接通过注解驱动 mvc:annotation-driven 的方式进行数据校验。Spring 的 LocalValidatorFactoryBean 既实现了 Spring 的 Validator 接口也实现了 JSR 303 的 Validator 接口。只要在Spring容器中定义了一个LocalValidatorFactoryBean即可将其注入到需要数据校验的 Bean中。Spring本身并没有提供JSR 303的实现所以必须将JSR 303的实现者的jar包放到类路径下。配置 mvc:annotation-driven 后SpringMVC 会默认装配好一个 LocalValidatorFactoryBean通过在处理方法的入参上标注 Validated 注解即可让 SpringMVC 在完成数据绑定后执行数据校验的工作。
2操作演示
导入依赖
!-- 校验注解 --
dependencygroupIdjakarta.platform/groupIdartifactIdjakarta.jakartaee-web-api/artifactIdversion9.1.0/versionscopeprovided/scope
/dependency!-- 校验注解实现--
!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator --
dependencygroupIdorg.hibernate.validator/groupIdartifactIdhibernate-validator/artifactIdversion8.0.0.Final/version
/dependency
!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator-annotation-processor --
dependencygroupIdorg.hibernate.validator/groupIdartifactIdhibernate-validator-annotation-processor/artifactIdversion8.0.0.Final/version
/dependency
应用校验注解
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import org.hibernate.validator.constraints.Length;/*** projectName: com.atguigu.pojo*/
public class User {//age 1 age 150Min(10)private int age;//name 3 name.length 6Length(min 3,max 10)private String name;//email 邮箱格式Emailprivate String email;public int getAge() {return age;}public void setAge(int age) {this.age age;}public String getName() {return name;}public void setName(String name) {this.name name;}public String getEmail() {return email;}public void setEmail(String email) {this.email email;}
} handler 标记和绑定错误收集
RestController
RequestMapping(user)
public class UserController {/*** Validated 代表应用校验注解! 必须添加!*/PostMapping(save)public Object save(Validated RequestBody User user,//在实体类参数和 BindingResult 之间不能有任何其他参数, BindingResult可以接受错误信息,避免信息抛出!BindingResult result){//判断是否有信息绑定错误! 有可以自行处理!if (result.hasErrors()){System.out.println(错误);String errorMsg result.getFieldError().toString();return errorMsg;}//没有,正常处理业务即可System.out.println(正常);return user;}
} 3易混总结 NotNull (包装类型不为null)、NotEmpty(集合类型长度大于0) 、NotBlank(字符串不为null切不为 字符串 都是用于在数据校验中检查字段值是否为空的注解但是它们的用法和校验规则有所不同。 4. 文件上传和下载
4.1 文件上传
1文件上传表单页面
位置index.xml
第一点请求方式必须是 POST第二点请求体的编码方式必须是 multipart / form-data通过form 标签的 enctype 属性设置第三点使用 input 标签、type 属性设置为 file 来生成文件上传框
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
bodyform action/save/picture methodpost enctypemultipart/form-data昵称input typetext namenickName value龙猫 /br/头像input typefile nameheadPicture /br/背景input typefile namebackgroundPicture /br/button typesubmit保存/button/form
/body
/html 2springmvc 环境要求
pom.xml 添加依赖
!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --
dependencygroupIdcommons-fileupload/groupIdartifactIdcommons-fileupload/artifactIdversion1.3.1/version
/dependency
配置文件上传处理器springmvc配置
!-- 文件上传处理器,可处理 multipart/* 请求并将其转换为 MultipartFile 对象--
bean idmultipartResolverclassorg.springframework.web.multipart.support.StandardServletMultipartResolver
/bean
注CommonsMultipartResolver 的 bean 的 id必须是multipartResolver 如果不是这个值会在上传文件时报错 在 web.xml 文件中添加 Multipart 配置
servletservlet-nameyourAppServlet/servlet-nameservlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-classmultipart-config!-- 定义文件上传时所需的最大值单位为字节 --max-file-size10485760/max-file-size!-- 定义单个上传文件的最大值单位为字节 --max-request-size20971520/max-request-size!-- 定义内存中存储文件的最大值超过此大小的文件会写入到硬盘中 --file-size-threshold5242880/file-size-threshold/multipart-configload-on-startup1/load-on-startup
/servlet
3handler 方法接收数据
/*** 上传的文件使用 MultipartFile 类型接收其相关数据* param nickName* param picture* param backgroundPicture* return* throws IOException*/
PostMapping (picture)
public String upload(String nickName, RequestParam(headPicture) MultipartFile picture, RequestParam(backgroundPicture)MultipartFile backgroundPicture) throws IOException {System.out.println(nickName);String inputName picture.getName();System.out.println(文件上传表单项的 name 属性值 inputName);// 获取这个数据通常都是为了获取文件本身的扩展名String originalFilename picture.getOriginalFilename();System.out.println(文件在用户本地原始的文件名 originalFilename);String contentType picture.getContentType();System.out.println(文件的内容类型 contentType);boolean empty picture.isEmpty();System.out.println(文件是否为空 empty);long size picture.getSize();System.out.println(文件大小 size);byte[] bytes picture.getBytes();System.out.println(文件二进制数据的字节数组 Arrays.asList(bytes));InputStream inputStream picture.getInputStream();System.out.println(读取文件数据的输入流对象 inputStream);Resource resource picture.getResource();System.out.println(代表当前 MultiPartFile 对象的资源对象 resource);return home;
}4MultipartFile 接口 5文件转存
① 底层机制 ② 本地转存