SpringMVC(三)
数据校验
只做前端校验是不安全的
在重要数据一定要加上后端验证
JSR303 数据验证
在bean属性上添加JSR 303的注解
JSR303:规范-----Hibernate Validator(第三方校验框架)实现
SpringMVC如何使用Hibernate Validator做JSR303数据校验
1、导入Hibernate Validator校验框架的jar包
* hibernate-validator-5.0.0.CR2.jar
* hibernate-validator-annotation-processor-5.0.0.CR2.jar
* classmate-0.8.0.jar
* jboss-logging-3.1.1.GA.jar
* validation-api-1.1.0.CR1.jar
* 有几个带el的jar包不导入,因为tomcat中自带el的jar包,tomcat7.0以上el表达式比较强大
* tomcat7.0以下则需要导入带el的jar包
* tomcat7.0以下将带el的几个jar包放在tomcat的lib文件夹下
2、在bean属性上标注注解
3、在SpringMVC封装对象的时候,告诉SpringMVC这个javaBean需要校验
4、如何知道校验成功还是失败
给需要校验的javaBean后面紧跟一个BindingResult
这个BindingResult就是封装前一个bean的校验结果
5、根据不同的校验结果决定怎么办---->hasError
6、在页面回显错误信息
1)使用form:errors取出错误信息
2)原生表单如何获取校验信息—>BindingResult
在控制台显示错误信息
在请求域中(页面)显示错误信息
自定义错误信息的显示
国际化错误信息的显示:有中英文的错误信息
如何定制错国际化误信息提示
1、编写国际化的文件
errors_zh_CN.properties
errors_en_US.properties
2、如何编写错误文件中的key
每一个字段发生错误以后,都会有自己的错误代码
国际化文件中错误消息的key必须对应一个错误代码
//错误代码
Field error in object 'employee' on field 'birth':
rejected value [Aa];
codes [typeMismatch.employee.birth,typeMismatch.birth,typeMismatch.java.util.Date,typeMismatch];
arguments [org.springframework.context.support.DefaultMessageSourceR
//code错误信息
codes
[
Email.employee.email, 校验规则.隐含模型中这个对象的key.对象的属性
Email.email, 校验规则.属性名
Email.java.lang.String, 校验规则.属性类型
Email
];
1、Email.employee.email:隐含模型中employee对象的email属性发生了@Email校验错误,就会提示Email.employee.email
2、Email.email:所有的email属性只要发生了@Email错误,就会提示Email.email
3、Email.java.lang.String:只要String类型发生了@Email错误,就会提示Email.java.lang.String
4、Email:只要发生了@Email校验错误,就会提示Email
3、让SpringMVC管理国际化资源文件
//Springmvc.xml
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="errors"></property>
</bean>
4、页面取出错误信息---->form:errors
修改非hibernate注解默认错误提示信息
高级国际化
动态传入参数信息
字母顺序max{1}, min{2}, {0}–>属性名
message指定错误信息(不能国际化)
在注解中添加message=“”,但是不能国际化
SpringMVC支持ajax
SpringMVC简单使用ajax
1、原生javaWeb
1)导入GSON
2)返回的数据用GSON转成json
3)写出去
2、SpringMVC-ajax
1)导包
jackson-annotations-2.1.5.jar
jackson-core-2.1.5.jar
jackson-databind-2.1.5.jar
2)写配置
常规
@JsonIgnore
@JsonFormat
ajax获取所有员工
<%
pageContext.setAttribute("ctp", request.getContextPath());
%>
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
</head>
<body>
<%=new Date() %>
<a href="${ctp }/getallajax">ajax获取所有员工</a><br/>
<script type="text/javascript">
$("a:first").click(function(){
//1、发送ajax获取所有员工上
$.ajax({
url:"${ctp}/getallajax",
type:"GET",
success:function(data){
console.log(data);
}
});
return false; //点击链接禁用默认超链接,改为发送ajax请求
});
</script>
在页面输出所有员工信息
RequestBody获取请求体
上传图片
上传txt文档
SpringMVC-ajax发送json数据到服务器
<script type="text/javascript">
$("a:first").click(function() {
//点击发送ajax请求,请求带的数据是json
var emp = {
lastName : "张三",
email : "aaa@aa.com",
gender : 0
};
//alert(typeof emp); -->object
//emp-js对象转为json对象
var empStr = JSON.stringify(emp);
//alert(typeof empStr); -->String
$.ajax({
url : '${ctp}/testRequestBody',
type : "POST",
data : empStr,
//contentType设置请求体类型为application/json
contentType : "application/json",
success : function(data) {
alert(data);
}
});
return false; //禁用默认超链接,改为发ajax请求
});
</script>
HttpEntity获取请求头信息
@RequestBody直接把数据放在响应体
HttpEntity可以获取请求头和请求体
@ResponseBody直接把数据放在响应体
ResponseEntity设置响应体、响应头、状态码
SpringMVC文件下载(了解)
HttpMessageConverter(了解)
文件上传
单文件上传
步骤
MultipartFile file封装当前文件的信息,调用transferTo保存
多文件上传
/\
||
||
||
||
\/
拦截器
单拦截器运行流程
/**
* 1、实现HandlerInterceptor接口
* 2、在SpringMVC配置文件中注册这个拦截器的工作;
* 配置这个拦截器来拦截哪些请求的目标方法;
*/
public class MyFirstInterceptor implements HandlerInterceptor {
/**
* 目标方法运行之前运行
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyFirstInterceptor...preHandle...");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("MyFirstInterceptor...postHandle...");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("MyFirstInterceptor...afterCompletion");
}
}
配置拦截器
<!-- 测试拦截器 -->
<mvc:interceptors>
<!--配置某个拦截器;默认是拦截所有请求的; -->
<bean class="com.atguigu.controller.MyFirstInterceptor"></bean>
<!-- 配置某个拦截器更详细的信息 -->
<mvc:interceptor>
<!-- 只来拦截test01请求 -->
<mvc:mapping path="/test01"/>
<bean class="com.atguigu.controller.MySecondInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
测试
@Controller
public class InterceptorTestController {
@RequestMapping("/test01")
public String test01(){
System.out.println("test01....");
//int i =10/0;
return "success";
}
}
单拦截器运行流程
多拦截器运行流程
拦截器a------>拦截器b---------
拦截器a <-----拦截器b <------
拦截器运行流程源码
两个拦截器都放行
源码开始
||
|| 获取处理器
\/
||
|| 获取适配器
\/
||
|| 执行目标方法
\/
=================================================
||
||
\/
||
|| 有异常进入postHandle
\/
|| postHandle有异常显抛出dispatchaException
|| 没有异常进入页面渲染
\/
||
||
\/
|| 不管processDiispatchResult方法是否异常
|| 都会来到AfterCompletion
\/
两个拦截器放行第一个,第二个不放行
源码开始
|| step into applyHandle
|| 只要有一个拦截器返回false就执行triggerAfterCompletion
|| 执行完triggerAfterCompletion就返回false
|| triggerAfterCompletion返回false—>!mappedHandler.applyPreHandle为true,执行return
\/
|| finally
||
\/
拦截器流程总结
国际化
简单国际化
国际化文件
配置Springmvc.xml
取出信息
login
国际化区域信息解析
Springmvc九大组件初始化会初始化localeResolver
step into
localeResover接口有2个方法
step into
step into
程序中获取国际化信息
点击链接切换国际化
自定义区域解析器实现切换国际化
区域解析器初始化过程
配置自定义区域解析器
public class MyLocaleResolver implements LocaleResolver {
/**
* 解析返回locale
*/
@Override
public Locale resolveLocale(HttpServletRequest req) {
// TODO Auto-generated method stub
// zh_CN
Locale l = null;
String localeStr = req.getParameter("locale");
//如果带了locale参数就用参数指定的区域信息,如果没带就用请求头的
if (localeStr != null && !"".equals(localeStr)) {
l = new Locale(localeStr.split("_")[0], localeStr.split("_")[1]);
} else {
l = req.getLocale();
}
return l;
}
/**
* 修改locale
*/
@Override
public void setLocale(HttpServletRequest arg0, HttpServletResponse arg1,
Locale arg2) {
throw new UnsupportedOperationException(
"Cannot change HTTP accept header - use a different locale resolution strategy");
}
}
测试
调试源码
看到使用的是自定义的区域解析器
使用sessionLocaleResovler实现点击链接切换国际化
配置
Filter与拦截器
filter是JavaWeb的三大组件,tomcat启动创建filter对象
filter无法加到ioc容器中,无法在ioc容器中拿到其他组件
filter只有一个doFilter方法
拦截器是配置在ioc容器中的,有pre、post、afterCompletion可以干预程序
可以拿到ioc的组件
filter是标准,脱离了SpringMVC仍然有效,而拦截器脱离SpringMVC无效
异常处理流程
SpringMVC通过HandlerExceptionResolver异常解析器处理目标方法的异常,HandlerExceptionResolver是SpringMVC的九大组件之一
异常解析器源码
测试异常
step into processDispatchResult
step into processHandlerException
三种异常解析器的使用场景
@ExceptionHandler单独处理一个类的异常
@ExceptionHandler单独处理一个类的异常,把异常方法写在该类中
@ExceptionHandler集中处理所有类的异常
@ExceptionHandler集中处理所有类的异常,把异常方法抽出到一个异常类
单独处理一个类的异常与全局处理异常优先级
@ResponseStatus
用在自定义的异常方法上,注意不能放在正常的方法上,否则正常的方法正确运行都会抛异常
DefaultHandlerExceptionResolver
判断是否SpringMVC自带的异常
异常运行源码
异常处理器轮流解析该异常
异常解析器匹配该异常
处理异常,返回
SimpleMappingExceptionResolver
通过配置的方式处理异常
源码
异常的model and view
SpringMVC运行流程
1、所有请求,前端控制器(DispatcherServlet)收到请求,调用doDispatch进行处理
2、根据HandlerMapping中保存的请求映射信息找到,处理当前请求的,处理器执行链(包含拦截器)
3、根据当前处理器找到他的HandlerAdapter(适配器)
step into gethandler
4、拦截器的preHandle先执行
5、适配器执行目标方法,并返回ModelAndView
6、拦截器的postHandle执行
7、处理结果;(页面渲染流程)
SpringMVC-Spring整合
可以合并配置文件,但是这样是SpringMVC-Spring单容器
SpringMVC和Spring分容器
分开扫描注解