类型转换概述
- 概述
- 请求参数绑定的过程中存在数据类型转换的问题
- 自动类型转换
- 比如:客户端发送给服务器的是"100",服务器用int来接收。
- 手动类型转换
- 有一些数据类型无法自动类型转换,比如:日期。
日期类型格式转换
-
概述
-
SpringMVC有内置一个DateFormatter,默认格式是"yyyy/MM/dd"
-
代码实现
<mvc:annotation-driven conversion-service="formattingConversionService"></mvc:annotation-driven> <bean id="formattingConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="formatters"> <set> <!--修改内置DateFormatter的格式--> <bean class="org.springframework.format.datetime.DateFormatter"> <property name="pattern" value="yyyy-MM-dd"></property> </bean> </set> </property> </bean>
public class User { private Integer userId; private String userName; private String userPwd; private Double money; @DateTimeFormat(pattern = "yyyy-MM-dd") private Date birthday; }
自定义类型转换器
-
概述
- 之前是修改内置日期类型转换器的格式,
- 现在是自定义日期类型转换器。
-
加粗样式开发步骤
- ①自定义Convert类实现Convert接口
- ②编写spring-mvc.xml
- 配置自定义Convert类
-
①自定义Convert类实现Convert接口
/** * <S, T> : S: source,原始数据类型 , T: target , 目标数据类型 */ public class MyDateConverter implements Converter<String, Date> { @Override public Date convert(String source) { //source : 原始日期字符串 try { Date date = new SimpleDateFormat("yyyy-MM-dd").parse(source); return date; } catch (ParseException e) { e.printStackTrace(); } return null; } }
-
②编写spring-mvc.xml
<mvc:annotation-driven conversion-service="formattingConversionService"></mvc:annotation-driven> <bean id="formattingConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.atguigu.convert.MyDateConverter"></bean> </set> </property> </bean>
类型转换BindingResult接口
-
概述
-
类型转换失败,跳转到一个400错误页面,体验不好;应该要跳转一个自定义错误页面,并展示合适的错误提示信息。
-
BindingResult包含了错误信息。
-
代码实现
@RequestMapping("/convert/testConvert01") public String testConvert01( User user ,BindingResult bindingResult, Model model ){ //出错时,从BindingResult获取错误信息 if (bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldError(); //birthday String fieldName = fieldError.getField(); String defaultMessage = "日期格式错误!"; model.addAttribute(fieldName + "ErrorMsg",defaultMessage); //跳转到自定义错误页面,并展示错误提示信息 return "error"; } System.out.println("user = " + user); return "index"; }
-
注意事项
- An Errors/BindingResult argument is expected to be declared immediately after the model attribute
- BindingResult接口必须放在javabean属性后面紧挨着,否则报上述错误!!!
表单校验概述
- 概述
- 之前,在javaweb阶段,我们使用javascript+正则表达式完成了客户端的表单校验;但是,可以通过一些方式绕过客户端的表单校验。
- 现在,也需要在服务器代码中加入表单校验。
- 客户端校验
- 使用js+正则表达式
- 服务器校验
- 使用校验框架
校验框架入门
-
常用注解
-
开发步骤
- ①引入依赖
- hibernate-validator
- ②改造javabean
- 使用validator注解
- ③编写前端代码
- ④编写后台代码
- ①引入依赖
-
①引入依赖
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.17.Final</version> </dependency>
-
②改造javabean
public class User { private Integer userId; @NotBlank(message = "账户不能为空!") private String userName; @NotBlank(message = "密码不能为空!") private String userPwd; @NotNull(message = "金额不能为空!") @Min(value = 0 , message = "金额不能低于0元") @Max(value = 1000000 ,message = "金额不能高于1000000元") private Double money; @DateTimeFormat(pattern = "yyyy-MM-dd") private Date birthday; @NotBlank(message = "邮箱不能为空!") @Email(message = "邮箱格式错误!") private String email; @NotBlank(message = "手机号不能为空!") @Pattern(regexp = "[1]{1}[356789]{1}[0-9]{9}" ,message = "手机号格式错误!") private String phoneNum; }
-
③编写前端代码
<form th:action="@{/validator/testValidator1}"> 账户:<input type="text" name="userName"><br> 密码:<input type="text" name="userPwd"><br> 薪资:<input type="text" name="money"><br> 生日:<input type="text" name="birthday"><br> 邮箱:<input type="text" name="email"><br> 电话:<input type="text" name="phoneNum"><br> <button type="submit">提交</button> </form>
-
④编写后台代码
@RequestMapping("/validator/testValidator1") public String testValidator1(@Valid User user){ System.out.println("user = " + user); return "index"; }
校验框架引入BindingResult接口
-
代码实现
@RequestMapping("/validator/testValidator2") public String testValidator2(@Valid User user , BindingResult bindingResult , Model model){ System.out.println("user = " + user); //有错误时,保存错误提示信息,并跳转页面展示 if (bindingResult.hasErrors()) { List<FieldError> fieldErrorList = bindingResult.getFieldErrors(); for (FieldError fieldError : fieldErrorList) { //获取每一个错误信息 String fieldName = fieldError.getField(); String errorMsg = fieldError.getDefaultMessage(); //错误1 : 生日为空! //错误2 : 生日格式错误! 需要处理. if ("birthday".equals(fieldName) && errorMsg.startsWith("Failed")) { model.addAttribute(fieldName + "ErrorMsg","生日格式错误!"); } else { model.addAttribute(fieldName + "ErrorMsg",errorMsg); } } return "demo02"; } return "index"; }
<form th:action="@{/validator/testValidator2}"> 账户: <input type="text" name="userName"> <span th:text="${userNameErrorMsg}" style="color: red"></span> <br> 密码: <input type="text" name="userPwd"> <span th:text="${userPwdErrorMsg}" style="color: red"></span> <br> 薪资:<input type="text" name="money"> <span th:text="${moneyErrorMsg}" style="color: red"></span> <br> 生日:<input type="text" name="birthday"> <span th:text="${birthdayErrorMsg}" style="color: red"></span> <br> 邮箱:<input type="text" name="email"> <span th:text="${emailErrorMsg}" style="color: red"></span> <br> 电话:<input type="text" name="phoneNum"> <span th:text="${phoneNumErrorMsg}" style="color: red"></span> <br> <button type="submit">提交</button> </form>
拦截器概述
- 概述
- 就是在Handler方法之前执行的组件。
- 拦截器VS过滤器
- 相同点
- 都需要执行过滤和放行
- 不同点
- 所在容器不同
- 拦截器在Spring容器
- 过滤器在tomcat容器
- 作用范围不同
- 拦截器只能拦截Spring容器中的资源
- 过滤器可以拦截所有资源
- IOC容器支持
- 拦截器可以直接使用IOC容器中的资源
- 过滤器不能直接使用IOC容器中的资源
- 所在容器不同
- 相同点
拦截器入门
-
常用方法
- preHandle : 在Handler方法之前执行,预处理
- postHandle : 在Handler方法之后执行,在视图渲染之前执行
- afterCompletion : 在Handler方法之后执行,在视图渲染之后执行
-
开发步骤
- ①自定义拦截器类实现HandlerInterceptor接口
- ②编写spring-mvc.xml
- 配置自定义拦截器类
- ③代码测试
-
①自定义拦截器类实现HandlerInterceptor接口
public class MyInterceptor1 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //在Handler方法之前执行 System.out.println("MyInterceptor1 preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { //在Handler方法之后执行,渲染视图之前执行 System.out.println("MyInterceptor1 postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //在Handler方法之后执行,渲染视图之后执行 System.out.println("MyInterceptor1 afterCompletion"); } }
-
②编写spring-mvc.xml
<mvc:interceptors> <bean class="com.atguigu.interceptor.MyInterceptor1"></bean> </mvc:interceptors>
-
③代码测试
拦截器拦截路径
-
概述
- 默认情况下,拦截器会拦截Spring容器中的所有资源。
-
代码实现
<mvc:interceptors> <!--精确匹配--> <!-- <mvc:interceptor> <mvc:mapping path="/interceptor/testInterceptor1"/> <bean class="com.atguigu.interceptor.MyInterceptor1"></bean> </mvc:interceptor> --> <!--匹配单层路径--> <!-- <mvc:interceptor> <mvc:mapping path="/interceptor/*"/> <bean class="com.atguigu.interceptor.MyInterceptor1"></bean> </mvc:interceptor> --> <!--匹配多层路径--> <!-- <mvc:interceptor> <mvc:mapping path="/interceptor/**"/> <bean class="com.atguigu.interceptor.MyInterceptor1"></bean> </mvc:interceptor> --> <mvc:interceptor> <mvc:mapping path="/interceptor/**"/> <mvc:exclude-mapping path="/interceptor/testInterceptor1"/> <bean class="com.atguigu.interceptor.MyInterceptor1"></bean> </mvc:interceptor> </mvc:interceptors>
多拦截器配置
-
总结
- 先配置,先拦截,后放行。
-
代码实现
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/interceptor/**"/> <bean class="com.atguigu.interceptor.MyInterceptor1"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/interceptor/**"/> <bean class="com.atguigu.interceptor.MyInterceptor2"></bean> </mvc:interceptor> </mvc:interceptors>
文件上传
-
概述
- 通过浏览器将本地电脑中文件上传到服务器电脑中。
-
开发步骤
- ①引入相关依赖
- fileupload
- ②编写前端代码(三要素)
- 请求方式=post
- enctype=“multipart/form-data”
- 文件上传项
- ③编写spring-mvc.xml
- 配置文件上传解析器
- ④编写后台代码
- 编写文件上传逻辑代码
- ①引入相关依赖
-
①引入相关依赖
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency>
-
②编写前端代码(三要素)
<form th:action="@{/file/upload}" enctype="multipart/form-data" method="post"> 文件:<input type="file" name="myFile"><br> <button type="submit">上传</button> </form>
-
③编写spring-mvc.xml
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设置上传文件的最大尺寸为5MB --> <property name="maxUploadSize"> <!--1TB、1GB、1MB、1KB、1byte--> <value>5242880</value> </property> </bean>
-
④编写后台代码
@Autowired private ServletContext servletContext; @RequestMapping("/file/upload") public String upload(MultipartFile myFile) throws IOException { //myFile : 浏览器上传文件的信息 //获取upload目录的真实磁盘路径 String uploadDirPath = servletContext.getRealPath("upload"); File uploadDirFile = new File(uploadDirPath); if (!uploadDirFile.exists()){ //创建upload目录 uploadDirFile.mkdir(); } //girl1.jpg String originalFilename = myFile.getOriginalFilename(); //fdsafadsfdsaf.jpg String[] fileNames = originalFilename.split("[\\.]"); String newFileName = UUID.randomUUID().toString().replaceAll("-","") + "." + fileNames[1]; File destFile = new File(uploadDirPath + File.separator + newFileName); myFile.transferTo(destFile); return "index"; }
文件下载
-
开发步骤
- ①读取下载文件的内容
- ②设置响应头
- Content-Type(下载文件类型)
- Content-Disposition(弹出下载窗口)
- ③设置下载状态
-
代码实现
@RequestMapping("/file/download") public ResponseEntity<byte[]> download(String fileName) throws Exception { //①读取下载文件的内容,bytes : 下载文件的内容 String downloadPath = servletContext.getRealPath("upload") + File.separator + fileName; BufferedInputStream bis = new BufferedInputStream(new FileInputStream(downloadPath)); byte[] bytes = new byte[bis.available()]; bis.read(bytes); //②设置响应头, headers : 设置响应头 , Content-Type(下载文件类型) , Content-Disposition(弹出下载窗口) MultiValueMap<String, String> headers = new HttpHeaders(); headers.add("Content-Type", servletContext.getMimeType(fileName)); headers.add("Content-Disposition", "attachement;filename=" + fileName); //③设置下载状态, status : 下载的状态 HttpStatus status = HttpStatus.OK; return new ResponseEntity<>(bytes, headers, status); }
ufferedInputStream(new FileInputStream(downloadPath));
byte[] bytes = new byte[bis.available()];
bis.read(bytes);
//②设置响应头, headers : 设置响应头 , Content-Type(下载文件类型) , Content-Disposition(弹出下载窗口)
MultiValueMap<String, String> headers = new HttpHeaders();
headers.add(“Content-Type”, servletContext.getMimeType(fileName));
headers.add(“Content-Disposition”, “attachement;filename=” + fileName);
//③设置下载状态, status : 下载的状态
HttpStatus status = HttpStatus.OK;
return new ResponseEntity<>(bytes, headers, status);
}