springmvc教程
SpringMVC
-
用来简化web应用开发的mvc框架
-
五大组件
-
DispatcherServlet (前端控制器)
-
HandlerMapping
-
Controller (处理器,业务处理)
-
ModelAndView
-
ViewResolver (视图解析器)解析成 jsp还是excel还是json还是其他视图
2.1组件的关系
过滤器在Tomcat里,前段控制器接收到请求,进行过滤,拦截器在前端控制器和Controller之间。
前端控制器接收到请求,根据HandlerMapping的规则调用相应的controller处理业务逻辑,处理器把数据封装成一个ModelAndView对象,这个对象包含一个视图名,前端处理器根据ViewResolver试图解析器响应输出。 HelloWeb DispatcherServlet初始化时,框架将尝试从位于应用程序的WebContent/WEB-INF目录中的名为[servlet-name]-servlet.xml的文件加载应用程序上下文。可以通过在web.xml文件中添加servlet侦听器ContextLoaderListener来自定义此文件名和位置 如下: 可以有多个DispatcherServlet,是通过名字来区分的。每一个DispatcherServlet有自己的WebApplicationContext上下文对象。listenner监听的是spring的父上下文,父上下文容器中保存数据源、服务层、DAO层、事务的Bean。子上下文容器中保存Mvc相关的Action的Bean.子可以访问父的beean,相反不能,
上中是传统方式,也可以简单方式, 不使用listener监听器来加载spring的配置文件,只使用DispatcherServlet来加载spring的配置,不要父子上下文,只使用一个DispatcherServlet,事情就简单了
事务控制在服务层。
<web-app...>
<!-------- DispatcherServlet definition goes here----->....<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/HelloWeb-servlet.xml</param-value></context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class></listener></web-app>
编程步骤:
2.1新建maven,导入spring-webmvc包,spring的配置文件
2.2在web.xml中配置DispatcherServlet
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--这个参数是自动创建容器,加载配置文件,springmvc配置文件默认地址再web-inf下的${servlet-name}-servlet.xml-->
<init-param>
<param-name>ContextConfigLocation</param-name>
<!--多个配置文件可以逗号分开,或者使用*通配符-->
<param-value>classpath:spirng-*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
2.3 配置ContextLoaderListener,把spring容器放入context中。启动web容器,加载applicationcontext配置文件,这个是spring容器,所有应用的上下文,controller service等,一个程序可以又很多dispatcherservlet的上下文,所以再dispatcherservlet中制定init-paramer制定特定的springmvc的webxml配置文件, ContextLoaderListener作为监听器,会监听web容器相关事件,在web容器启动或者关闭时触发执行响应程序。具体地,ContextLoaderListener继承ContextLoader类并实现了ServletContextListener接口。
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--指定spring配置位置,默认的web-inf下的applicationContext.xml-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
2.4 对模型视图名称的解析,即在模型视图名称添加前后缀(如果最后一个还是表示文件夹,则最后的斜杠不要漏了) 使用JSP
<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/><!--设置JSP文件的目录位置-->
<property name="suffix" value=".jsp"/>
</bean>
2.5 写一个controller类, 在类名前加上注解 @Controller
-
处理的方法名称不作要求,返回值有两种类型,String(视图名)和ModelAndView类型,string内部也是包装成ModelAndView
-
在类名前或者方法前加上 @RequestMapping(“/hello.do”)告诉前端控制器,请求地址对应哪个处理方法。可以把共同的包提到类前,比如都是/a/*.do,可以在类名前写@RequestMapping(“/a”)。
-
用法:method指定请求的方式get post delete post,produces指定返回的数据格式,consumes指定接收的数据格式@RequestMapping(value = "/accept",method = RequestMethod.GET||RequestMethod.GET, produces = {"application/json;charset=UTF-8", "application/xml"}, consumes = "text/html" )
-
另外,在springmvc配置文件中要写上组件扫描,加上一个MVC注解扫描,<mvc:annotation-driver/>,识别@RequestMapping(“”),<mvc:annotation-driven /> 会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter 与ExceptionHandlerExceptionResolver 三个bean
3.如何获取浏览器发来的请求参数
方式一:使用request对象,前端控制器会把这个对象作为参数传给方法
public String check(HttpServletRequest req){}
方式二:使用请求参数名作为参数,name和pwd是请求页面表单的参数名,如 果不一致,可以用@RequestParam(“”)注解(意义不大),相同的name可以用数组接收。
public String check(String name,String pwd){)
public String check(String name,@RequestParam(“pwd”) String pass){)
方式三:使用JavaBean的方式(内部机制是前端控制器把请求参数赋值给java类对应的值)
新建一个bean,前端写属性,参数传入bean,springmvc会自动封装成bean类型。
2.@PathVariable @RequestParam @RequestHeader的使用
@PathVariable:/helloworld/{id} 路径传参
@RequestParam /helloworld?name=zhouyang get请求后面传参数
@RequestHeader 获取header头部信息的参数
@RequestMapping(value="/helloworld/{id}",method=RequestMethod.GET)
public String helloget(@PathVariable("id") String id,@RequestParam(value="name",required=true) String name,@RequestHeader("cookie") String cookie){
System.out.println("getwefdg"+id+"FFF:"+name+"DDD:"+cookie);
return "success"; }
-
怎样向页面传值(springmvc会 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器)
第一种方式:使用请求对象,使用request对象绑定数据,再转发给jsp
Req.setAttribute(str,object),不用获取转发器。
注:默认情况下,前段控制器使用转发机制转发给对应的jsp
@RequestMapping("/login3.do")
public String check3(Sudent sudent,HttpServletRequest req){
System.out.println("帐号是: "+sudent.getName());
req.setAttribute("name", sudent.getName());
return "index";
}
第二种方式:使用ModelMap Model Map等作为方法的参数,使用modelMap的addAttribute方法绑定数据,其底层是request的setAttribute方法,Spring MVC 在调用方法前会创建一个隐
含的模型对象作为模型数据的存储容器。
@RequestMapping("/login4.do")
public String check4(String name,String pwd,ModelMap model){
model.addAttribute("name", name);
return "index";}
第三种方式:使用Session对象绑定数据
public String check4(Sudent student,HttpSession session){
session.setAttribute("name", student.getName());
return "index";}
第四种方式:使用ModelAndView作为方法的返回值(不建议)
//底层是把其属性值放在request.setAttribute(),绑定名是map集合中的key
@RequestMapping("/login6.do")
public ModelAndView check6(HttpServletRequest req){
Map<String,Object> map = new HashMap<String,Object>();
String ename = req.getParameter("name");
map.put("name", ename);
return new ModelAndView("index",map);}
4.5 @SessionAttributes 控制器类上标注,模型中对应的属性暂存到 HttpSession 中, Spring MVC将存放在model中对应的数据暂存到 HttpSession 中 ,除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中
@SessionAttributes(value={ “user1”,“user2”},type="User.class"),可以指定key或者值得类型
在类上添加了@SessionAttributes
@SessionAttributes(value={"user"}) @Controller
public class UserController {
//先存在map中
@RequestMapping(value="/helloworld/testSeesion1",method=RequestMethod.GET)
public String helloget(Map<String,Student> map,HttpSession session){
Student student = new Student();
student.setAge(34);
student.setName("fsdf");
map.put("student",student);
return "success"; }
//从session中获取
@RequestMapping(value="/helloworld/testSeesion2",method=RequestMethod.GET)
public String helloget(Student student){
System.out.println(student.toString());
return "success";}
处理方法testSessionAttributes在model中存放了属性名为user的数据,
处理结束后,model里的数据会被放入到request中,页面通过request域可以获取到。
而这里使用了@SessionAttributes(value={“user”})将model中属性名为user的数据copy一份进了session域中.
4.6 @ModelAttribute :标注的方法会在每个调用方法前执行,
4.7Spring MVC环境,可以正常访问controller,但是通过viewResolver访问jsp会返回404错误。
dispatcher-servlet.xml resolver配置
<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/view/"/><!--设置JSP文件的目录位置-->
<property name="suffix" value=".jsp"/></bean>
web.xml中拦截规则如下
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern></servlet-mapping>
改正方式:方式一:将<url-pattern>/*<url-pattern>改成<url-pattern>/<url-pattern>后,方式二:mvc配置文件中加入<>
/和/*的区别:
< url-pattern > / <url-pattern > 不会匹配到.jsp,即:.jsp不会进入spring的 DispatcherServlet类 。
< url-pattern > /* <url-pattern > 会匹配*.jsp,会出现返回jsp视图时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。
关于web.xml的url映射规则:
< url-pattern>/<url-pattern> 会匹配到/login这样的路径型url,不会匹配到模式为*.jsp这样的后缀型url
< url-pattern>/*</url-pattern> 会匹配所有url:路径型的和后缀型的url(包括/login,.jsp,.js和*.html等),
1.@ModelAttribute注释void返回值的方法,会在调用其他requestMapping方法之前先调用。
@Controllerpublic class HelloWorldController {
@ModelAttribute
public void populateModel(@RequestParam String abc, Model model) {
model.addAttribute("attributeName", abc);
}
@RequestMapping(value = "/helloWorld")
public String helloWorld() {
return "helloWorld";
}}
2.标注在有返回值得方法前,如果有属性,就以该属性为key,存入数据模型中,等同model.put("student",student),没(“student”)没有属性就以返回的类型首字母小写作为key
@Controllerpublic class HelloWorldController {
@ModelAttribute("student")
public Student populateModel(@RequestParam String abc, Model model) {
model.addAttribute("attributeName", abc);
return new Student("zhouyang");
}
}}
3.和@RequestMapping连用,这时这个方法的返回值并不是表示一个视图名称,而是model属性的值,视图名称由RequestToViewNameTranslator根据请求"/helloWorld.do"转换为逻辑视图helloWorld。
Model属性名称有@ModelAttribute(value=””)指定,相当于在request中封装了key=attributeName,value=hi。
@Controller
2 public class HelloWorldController {
3 @RequestMapping(value = "/helloWorld.do")
4 @ModelAttribute("attributeName")
5 public String helloWorld() {
6 return "hi";
7 }
8 }
4. 标注在参数前,@ModelAttribute(value="student")Student student 没指定value那么以类首字母小写,去数据模型中获取对应给的object, 此时如果类没有标注@SessionAttributes,那么scope为request,如果标注了,那么scope为session,再将请求参数绑定在对象中,再传入入参
@RequestMapping(value = "/helloWorld")
9 public String helloWorld(@ModelAttribute("user") User user) {
10 user.setUserName("jizhou");
11 return "helloWorld";
12 }
整合pojo流程如下,使用情景:pojo中某些属性不能显示在前端,如pwd,更新时,前端传来的字段只是一部分,那么使用modelatt的方法从数据库中获取,存入模型中,然后方法传参用pojo,那么这样这样参数就是完整更新后的pojo
/**
* 1. 有 @ModelAttribute 标记的方法, 会在每个目标方法执行之前被 SpringMVC 调用!
* 2. @ModelAttribute 注解也可以来修饰目标方法 POJO 类型的入参, 其 value 属性值有如下的作用:
* 1). SpringMVC 会使用 value 属性值在 implicitModel 中查找对应的对象, 若存在则会直接传入到目标方法的入参中.
* 2). SpringMVC 会一 value 为 key, POJO 类型的对象为 value, 存入到 request 中.
*/
/**
* 运行流程:
* 1. 执行 @ModelAttribute 注解修饰的方法: 从数据库中取出对象, 把对象放入到了 Map 中. 键为: user
* 2. SpringMVC 从 Map 中取出 User 对象, 并把表单的请求参数赋给该 User 对象的对应属性.
* 3. SpringMVC 把上述对象传入目标方法的参数.
*
* 注意: 在 @ModelAttribute 修饰的方法中, 放入到 Map 时的键需要和目标方法入参类型的第一个字母小写的字符串一致!
*
* SpringMVC 确定目标方法 POJO 类型入参的过程
* 1. 确定一个 key:
* 1). 若目标方法的 POJO 类型的参数木有使用 @ModelAttribute 作为修饰, 则 key 为 POJO 类名第一个字母的小写
* 2). 若使用了 @ModelAttribute 来修饰, 则 key 为 @ModelAttribute 注解的 value 属性值.
* 2. 在 implicitModel 中查找 key 对应的对象, 若存在, 则作为入参传入
* 1). 若在 @ModelAttribute 标记的方法中在 Map 中保存过, 且 key 和 1 确定的 key 一致, 则会获取到.
* 3. 若 implicitModel 中不存在 key 对应的对象, 则检查当前的 Handler 是否使用 @SessionAttributes 注解修饰,
* 若使用了该注解, 且 @SessionAttributes 注解的 value 属性值中包含了 key, 则会从 HttpSession 中来获取 key 所
* 对应的 value 值, 若存在则直接传入到目标方法的入参中. 若不存在则将抛出异常.
* 4. 若 Handler 没有标识 @SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 则
* 会通过反射来创建 POJO 类型的参数, 传入为目标方法的参数
* 5. SpringMVC 会把 key 和 POJO 类型的对象保存到 implicitModel 中, 进而会保存到 request 中.
*
* 源代码分析的流程
* 1. 调用 @ModelAttribute 注解修饰的方法. 实际上把 @ModelAttribute 方法中 Map 中的数据放在了 implicitModel 中.
* 2. 解析请求处理器的目标参数, 实际上该目标参数来自于 WebDataBinder 对象的 target 属性
* 1). 创建 WebDataBinder 对象:
* ①. 确定 objectName 属性: 若传入的 attrName 属性值为 "", 则 objectName 为类名第一个字母小写.
* *注意: attrName. 若目标方法的 POJO 属性使用了 @ModelAttribute 来修饰, 则 attrName 值即为 @ModelAttribute
* 的 value 属性值
*
* ②. 确定 target 属性:
* > 在 implicitModel 中查找 attrName 对应的属性值. 若存在, ok
* > *若不存在: 则验证当前 Handler 是否使用了 @SessionAttributes 进行修饰, 若使用了, 则尝试从 Session 中
* 获取 attrName 所对应的属性值. 若 session 中没有对应的属性值, 则抛出了异常.
* > 若 Handler 没有使用 @SessionAttributes 进行修饰, 或 @SessionAttributes 中没有使用 value 值指定的 key
* 和 attrName 相匹配, 则通过反射创建了 POJO 对象
*
* 2). SpringMVC 把表单的请求参数赋给了 WebDataBinder 的 target 对应的属性.
* 3). *SpringMVC 会把 WebDataBinder 的 attrName 和 target 给到 implicitModel.
* 近而传到 request 域对象中.
* 4). 把 WebDataBinder 的 target 作为参数传递给目标方法的入参.
*/
@ModelAttribute
public void helloget(Map<String,Student> map){
Student student = new Student();
student.setAge(34);
student.setName("fsdf");
map.put("student",student);
}
@RequestMapping(value="/helloworld/testSeesion2",method=RequestMethod.POST)
public String helloget(@ModelAttribute(value="student")Student student){
//从模型中获取student的object,然后前端参数的对应值传入pojo,再把整个pojo当做参数入参。
System.out.println(student.toString());
return "success";}
5.rest风格的crud
form表单值支持get post请求,要使用put delete请求需要添加HiddenHttpMethodFilter过滤器
web.xml添加过滤器
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
前端
//HiddenHttpMethodFilter中有一个_method,使用一个hidden的input,指定name是_method,value是put或者delete,这样就能把post请求转换成这两种请求
<form action="helloworld/testrest/33" method="post">
<input type="hidden" name="_method" value="PUT" />
<input type="submit" value="Test Rest PUT"/>
</form>
后端
@RequestMapping(value="/helloworld/testrest/{id}",method=RequestMethod.DELETE)
- 如何重定向,转发
情形1:方法返回值是字符串,前端控制器建议浏览器访问toIndex.do地址
重定向:return “redirect:toIndex.do”
转发:return “forward:toIndex.do”
情形2:如果方法的返回值是ModelAndView,只要把viewName的字符串同上就行。例如
ModelAndView m = new ModelAndView(“redirect:toIndex.do”,Object);
6.Springmvc 表单标签
把模型数据中的属性和 HTML 表单元素相绑定,以实现表单数据更便捷编辑和表单值的回显
<form:form>:通过 GET 请求获取表单页面,而通过POST 请求提交表单页面,因此获取表单页面和提交表单页面的 URL 是相同的。只要满足该最佳条件的契约,<form:form> 标签就无需通过 action 属性指定表单提交的 URL,需要指modelAttribute 属性指定绑定的模型属性
form:input、form:password、form:hidden、form:textarea、form:radiobutton、form:radiobuttons/form:checkbox、form:checkboxs、form:select、form:option、form:errors:<form:errors path= “user *” />显示user开头的属性的错误值,也可以指定特定属性的错误值
7.数据转换 & 数据格式化 & 数据校验
通过反射机制对目标处理方法进行解析,将请求消息绑定到处理方法的入参中。springmvc内置了很多转换器
自定义转换器:
7.1自定义类MYConverter实现Converter接口,
7.2在容器中加入到factory,并注册到springmvc上下文
<!-- 转换器 -->
<bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!-- 给工厂注入一个新的类型转换器 -->
<property name="converters">
<list>
<!-- 配置自定义类型转换器 -->
<bean class="com.atguigu.springmvc.convert.MyConvert"></bean>
</list>
<!--在 annotation-driven 标签中引用配置的类型转换服务-->
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"/>
7.2<mvc:annotation-driven /> 会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter 与ExceptionHandlerExceptionResolver 三个bean
还支持:@DataTimeFormat(pattern="yyyy-MM-dd HH-mm-ss") :用在Date、Calendar、Long等时间类型的字段上
@NumberFormat对数据进行格式化
@Valid 对javabean进行验证
@RequestBody
@ResponseBody该注解用于将 Controller 的方法返回的对象,通过 HttpMessageConverter 接口转换为指定格式的数据如:json,xml 等,通过 Response 响应给客户端
7.3数据绑定@initBinder
完成表单到javabean的数据绑定, WebDataBinder 是 DataBinder的子类,返回方法是void,一般用 WebDataBinder 进行绑定,可以设置绑定的相关属性
@InitBinder
public void myDataBinder(WebDataBinder webDataBinder){
webDataBinder.setDisallowedFields("name");
}
7.4FormattingConversionService 有数据转换功能,又具有格式化的功能,<mvc:annotation-driven/> 默认创建的ConversionService 实例即为FormattingConversionServiceFactroyBean,这个类支持@DataTimeFormat @NumberFormat
7.5 数据校验,JSR303 作用在javabean的字段上,用于校验除实体类的接口参数,用于Controller上
@NotNull | 引用类型 | 注解元素必须非空
@Null | 引用类型 |元素为空
@Digits | byte,short,int,long及其包装器,BigDecimal,BigInteger,String| 验证数字是否合法。属性:integer(整数部分), fraction(小数部分)
@Future/@Past| java.util.Date, java.util.Calendar | 是否在当前时间之后或之前
@Max/@Min | byte,short,int,long及其包装器,BigDecimal,BigInteger | 验证值是否小于等于最大指定整数值或大于等于最小指定整数值
@Pattern | String |验证字符串是否匹配指定的正则表达式。属性:regexp(正则), flags(选项,Pattern.Flag值)
@Size | String, Collection, Map, 数组 | 验证元素大小是否在指定范围内。属性:max(最大长度), min(最小长度), message(提示,默认为{constraint.size})
@DecimalMax/@DecimalMin | byte,short,int,long及其包装器,BigDecimal,BigInteger,String | 验证值是否小于等于最大指定小数值或大于等于最小指定小数值
@Valid | |验证值是否需要递归调用
@Null
@NotNull
@AssertFalse
@AssertTrue
@DecimalMax(value) 不大于value的数值
@DecimalMin(value) 不小于value的数值
@Digits(integer,fraction) 整数部分不超过integer,小数部分不超过fraction
@Future 将来的日期
@Past 过去的日期
@Max(value) 不大于value的数值
@Min(value) 不小于value的数值
@Pattern(value) 满足指定正则表达式
@Size(max,min) 长度在min到max之间
@Email 被注释的元素必须是电子邮箱地址
@Length 字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range 被注释的元素必须在合适的范围内
1.在实体类加上验证注解 ,controller层加入@Validated验证,输入不能满足条件是,就会抛出异常,而后统一由异常中心处理也可以用BindingResult,但是用了这个后就必须手动处理异常,侵入了正常的逻辑过程,并不推荐
public class User {
private String id;
@NotEmpty(message = "用户名不能为空")
private String username;
@Size(min=6 ,max= 20 ,message = "密码最少6位,最高20位")
private String password;
}
@Controller
public class UserController {
@RequestMapping("/save")
public String save(@Validated User user, BindingResult result) {
if(result.hasErrors()) {
return "error";
}
return "success";
如何使用: Spring 的 LocalValidatorFactroyBean 既实现了 Spring 的Validator 接口,也实现了 JSR 303 的 Validator 接口。
②. 加入 hibernate validator 验证框架的 jar 包
③. 在 SpringMVC 配置文件中添加 <mvc:annotation-driven />,这个会自动配置LocalValidatorFactroyBean
④. 需要在 bean 的属性上添加对应的注解
⑤. 在目标方法 bean 类型的前面添加 @Valid 注解
2). 验证出错转向到哪一个页面 ?
如何自定义错误消息: 使用国际化 配置的名称格式为:注解名称.属性名称 Min.name
8@ResponseBody和@RequestBody
@ResponseBody是作用在方法上的,@ResponseBody 表示该方法的返回结果直接写入 HTTP response body 中,一般在异步获取数据时使用【也就是AJAX】,在使用 @RequestMapping后,返回值通常解析为跳转路径,但是加上 @ResponseBody 后返回结果不会被解析为跳转路径,而是直接写入 HTTP response body 中。 比如异步获取 json 数据,加上 @ResponseBody 后,会直接返回 json 数据。
@RequestBody 将 HTTP 请求正文插入方法中, 根据HTTP Request Header的content-Type的内容,通过适当的HttpMessageConverter转换成对象绑定入参。
@RequestMapping("/login.do")
@ResponseBody
public Object login(String name, String password, HttpSession session) {
user = userService.checkLogin(name, password);
session.setAttribute("user", user);
return new JsonResult(user);
}
需要加入json包
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
8.
- @RequestParam 可以把请求参数传递给请求方法
- @RequestHeader 绑定请求报头的属性值
- @CookieValue 可让处理方法入参绑定某个 Cookie 值
9.国际化
9.1 xml中配置ResourceBundleMessageSource
<bean id="" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="i18n"></property>
</bean>
9.2 配置资源文件
9.3 jsp中使用<fmt:meg>标签 使用
9.4 使用链接自动切换语言,下图是locale的运行原理
配置SessionLocaleResolve和LocaleChangeInterceptor
<!-- 配置 SessionLocalResolver -->
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver"></bean>
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean>
</mvc:interceptors>
//链接添加参数locale的属性值zh_CN或者en_US 实现中英文切换
前端:<a href="xx?locale=zh_CN">
10.文件上传
11.1 配置文件上传解析器
<!-- 文件上传,id必须设置为multipartResolver -->
<bean id="multipartResolver"
<!-- 设置文件上传大小 -->
<property name="maxUploadSize" value="5000000" />
<property name="defaultEncoding" value="utf-8" />
</bean>
11.2 页面 form写 enctype="multipart/form-data",
<form action="/SpringMVC006/fileUpload2" method="post" enctype="multipart/form-data">
<h1>采用multipart提供的file.transfer方法上传文件</h1>
<input type="file" name="file1">
11.3 springmvc中方法传入参数 MultipartFile file1参数进行使用
13.如何处理乱码问题
1.Get提交:在tomcat的server.xml中修改配置,
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8"/>
在表单的提交中,如果遇到中文字符会出现乱码,spring提供了一个CharacterEncodingFilter过滤器解决乱码,使用时注意只支持表单以POST方式提交,在web.xml中配置过滤器,而且页面编码和过滤器指定编码要一致。
问题:无论是get还是post请求,请求中文都能处理,但是当返回值是 String时会出现中文乱码,而当返回值是Map<String, Object>或者是其它类型时,并没有中文乱码的出现.
原因: 原因是这可以说是spring mvc的一个bug,spring MVC有一系列HttpMessageConverter去处理用@ResponseBody注解的返回值,如返回list或其它则使用 MappingJacksonHttpMessageConverter,返回string,则使用 StringHttpMessageConverter,而这个convert使用的是字符集是iso-8859-1,而且是final的。所以在当返回json中有中文时会出现乱码。
解决办法:手动配置返回的数据字符集 @RequestMapping(value = "***",produces={"application/json;charset=UTF-8","text/html;charset=UTF-8"})
14.spring的拦截器
客户端发出的请求,有些地址不能直接访问,比如要验证登录成功之后才能访问首页,使用session对请求验证,但是每个请求都验证太麻烦。
前端控制器收到请求后,先调用拦截器处理,再调用controller处理。
注:过滤器是Servlet中的组件,而拦截器是spring容器管理的组件。
如何写一个拦截器:
Step1:写一个java类,实现HandlerInterceptor接口,
Step2:在接口方法中实现拦截处理逻辑,比如进行session验证
Step2:在spring配置文件中配置拦截器,多个拦截器注意先后顺序
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="spring.MyHandlerInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
注意:path中/*只能拦截一层请求,比如这里只能拦截/x.do,如想拦截/x/x.do,使用/**表示拦截多层请求
拦截器接口有三个方法:
preHandle:前端控制器收到请求之后交给处理器处理之前,会先调用拦截器的preHandle方法,如果返回true,表示继续向后调用,否则处理完毕。
PostHandle:前端控制器交给处理器处理之后,Controller返回一个ModelAndview给前段控制器的时候,执行PostHandle,可以对ModelAndView对象进行修改。
afterCompletion:整个请求处理完毕之后,执行这个方法。
执行顺序,和拦截器定义的顺序对应:
preHandle按拦截器定义顺序调用,返回false后续的方法不执行
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用
postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有对应的preHandle返回true才调用,不需要全部拦截器返回true
controller只要有拦截器返回false就不执行
15.spring对异常的处理(异常要抛给表示层,spring才能处理)springmvc使用HandlerExceptionResolver进行处理整个流程中的异常。处理程序的异常,包括Handler映射、数据绑定以及目标方法执行时发生的异常
SpringMVC提供的HandlerExceptionResolver的实现类包括:
方式一:@ExceptionHandler
在控制器类中添加方法处理异常。当前controller中出现了异常就会在当前类中寻找异常处理,这里会跳转到相应的@ExceptionHandler返回相应的ModelAndView,如果想返回json等数据,可以在上面添加@ResponseBody返回json数据。
@Controller
@RequestMapping("/test")
public class KeywordController {
@RequestMapping("/info")
public String info() {
int a = 4/0;
return "success";
}
@ExceptionHandler({ArithmeticException.class})
//@ResponseBody
public ModelAndView handlerArithmeticException(Exception ex ){
System.out.println("出异常了:"+ex);
ModelAndView mv = new ModelAndView("error");
mv.addObject("exception", ex);
return mv;
}
方式二:使用 @controlleradvice 注解+@ExceptionHandler
s上面的只能处理当前controller的异常,为了处理全局异常,把业务逻辑和异常分开,当发生异常时去统一异常处理中心。
如果想要页面处理异常返回其他数据格式如json,可以在这个异常类上添加@ResponseBody注解,返回值自己需要的类型,和controller用法相同。
若发生异常,当前handler没 @ExceptionHandler处理异常,那么就去@ControllerAdvice标记的类中找@ExceptionHandler标记的方法处理异常
要返回异常界面的信息,不能用map传参,要使用ModelAndView返回界面。
@ControllerAdvice
public class HandeException{
@ExceptionHandler({ArithmeticException.class})
@ResponseBody
public StringHandlerException(Exception e){
return "异常信息"; }}
方式三:使用ResponseStatusExceptionResolver(若没找到方式二的处理方法,那么处理器就寻找这种方式处理),当方法中出现异常就会找到这个,返回相应的状态码。
//自定义异常类,controller中发生这个异常就会调用它。
@ResponseStatus(value=HttpStatus.BAD_REQUEST,reason="请求方法错误")
public class SpringMVCTestExceptionHandler extends RuntimeException{}
16 springmvc直接转发:不用写controller直接转发到success页面
<mvc:view-controller path="/testcontroller" view-name="success"/>
但是注意必须配置<mvc:annotation-driven></mvc:annotation-driven>,不然经过controller的其他控制器就不起作用了
17 springmvc对静态文件的访问,web.xml中场配置/拦截所有请求,所以静态资源也会被拦截
方式一:在springmvc的配置文件中加入<mvc:default-servlet-handler/> 建议写上这个。
-
Copy
-
<mvc:default-servlet-handler/>
- 方式二:在springmvc配置文件中手动指定静态资源路径
-
Copy
-
<!-- 设置静态资源不过滤 --><mvc:resources location="/css/" mapping="/css/**" /><mvc:resources location="/img/" mapping="/img/**" /><mvc:resources location="/js/" mapping="/js/**" /><mvc:resources location="/plugins/" mapping="/plugins/**" />

浙公网安备 33010602011771号