提示:本篇文章共15000字左右,篇幅比较长,大家可以通过目录点击直达你需要的模块,一篇文章帮你解决springmvc所有常用的知识点!
springmvc本质上其实就是一个servlet,他通过前台访问自己内置的servlet然后对数据进行操作,所以说他是web层或者说controller层框架。
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>com.test.controller.ServletTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet1</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
这是我们在java web时,配置的web.xml文件中的servlet,使用springmvc与其基本是同一个道理
springmvc配置:
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!-- 配置文件的路径,他是DispatcherServlet类的一个参数 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!-- 表示启动时立即加载 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<--! 这里的名称任意,与上面对应即可,作用是通过映射找到mvc的servlet类 -->
<servlet-name>springDispatcherServlet</servlet-name>
<!-- 这里表示servlet请求处理路径,/表示拦截所有的请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
通过上述方式,即可拦截所有请求,把所有请求都交给SpringMVC的DispatcherServlet去处理
然后我们还需要一个试图解析器:
视图解析器是用来对返回的数据和页面进行解析
在SpringMVC的配置文件中配置一个试图解析器的Bean:
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
视图解析器的类为InternalResourceViewResolver
<property name="prefix" value="/" />
<property name="suffix" value=".jsp" />
</bean>
这个类有两个属性:
Prefix:表示前置
Suffix:表示后置
他会给后台返回的数据加上前置和后置,然后响应给页面。
SpringMVC开发,现在我们一般使用注解,所以需要在配置文件中开启注解:
<context:component-scan
base-package="com.dcz.controller">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
package指定注解的扫描路径
context:include-filter 表示他只扫描Spring框架的@controller注解,其他的跳过。Spring和SpringMVC在一起使用时,这一步的作用是将这两个框架进行分离
最后,附上配置中的源码:
简单点理解,配置xml文件就是为了启动框架和给框架中的属性赋值。(这个说法并不规范,但是易于理解)
他的父类中有一个属性
负责保存mvc配置文件的路径
如果不指定springMVC配置文件路径,默认的地址为:WEB-INF/
默认的文件名为:
springMVC
Web.xml中配置的servletName的值-servlet.xml
例如springMVC-Servlet.xml
所谓的映射,就是前台访问后台,通过对应的路径去寻找对应的方法,在springmvc中,路径的寻找是基于@RequestMapping注解,他并不是去寻找类名、方法名,所以方法名称可以任意,但一般情况下需要遵循开发命名规范。
@RequestMapping有两个用法:
可以加在方法上,也可以加在类上面
参数列表中默认一般为映射的路径,前台通过访问该路径而访问controller的方法。
@RequestMapping(“/web”)
Public class TestController{
@RequestMapping(“/test”)
Public String test(){
//需要执行的代码
}
}
当类上面同时使用该注解时,会先去寻找类映射,在去寻找方法映射,一般用于请求很多,不同请求分组的情况,此时查找的路径应该为:项目下:web/test
当然@RequestMapping(“web/test/aaa”)也可以直接进行指定组合的路径,
@RequestMapping注解的属性
Value : 映射
Method:指定前台的请求方式,多个用逗号隔开,值为requestMethod的枚举类型(get、post、 delete、put)。
Params:参数值,多个参数可用大括号{}
{“name”}表示参数必须包含name值,
{“name=zs”}表示必须包含那么且值只能等于zs,
{“age!=23”}表示age不能等于23或者干脆没有age
{“!height”}表示不能包含hight
Value属性中同样支持通配符:
例如:@RequestMapping(“welcome/*/test”)
*表示匹配任意字符(0个或多个)(1个*号 )
**表示任意的目录@RequestMapping(“welcome/**/test”),表示多个目录,此时任意目录均可以, 例如:welcome/a/b/c/test
Welcome/a/test
Welcome/asd/asg/test …….
?表示单个字符:
@RequestMapping(“welcome/a?b/test”)
此时请求只有 Welcome/axb/test可以
他们两个注解都是用于前台向controller传递参数,controller用于接收的注解
@RequestParam:
这个注解最经常使用,加在方法的参数前,用于将指定的值赋值给注解后面的变量
他有三个常用属性:
1.value: 请求参数的参数名,作为参数映射名称,例如:test?name=zhangsan 则后台对应@RequestParam(“name”)
2.required:指定该值是不是前台必传,不传报错,值为true和false
3.defaultValue:指定参数默认值,在没有传值的情况下,默认为该值
@PathVariable
这个注解是可以将传递的参数值放在路径中,是一种使用url传值的方式:
请求:
后台:
此时 name的值为zs
将值放在url中,一般用于不需要保密的值
此处的处理模型数据,简单来说主要就是指的controller向前台页面传值的过程
处理模型数据:
如果跳转时,需要带数据,则可以使用ModelAndView、ModelMap、Model、java.util.map
他们都会将数据放在request作用域,以及注解@sessionAttributes、@ModelAttribute,这都是传值的方式
ModelAndView :既有数据,又有视图
ModelMap、Model、包括java.util.Map 这三个都是光有数据,只需要把数据存到里面,不需要返回,也不需要管理,Spring就会自动将数据加载到作用域
上述方法默认只能将数据存储到request作用域
Session中如何进行存储呢?
可以在类的前面加上注解@sessionAttributes()
@SessionAttributes(“user”)
//该括号内参数与存入值的key相同,则同时存入session域中
@Controller
public class CarController {
@Autowired
CarService service;
@RequestMapping("listCar.do")
public String listCar(Model model) {
User user = new User();
model.addAttribute("user", user);
//当方法中执行类似语句要将数据存入requset作用域时,如果key的值和类上面sessionAttributes(“”)
//注解的值相同时,则会同时存入session域中
//此时request和session中均有值
return "list";
}
}
@sessionAttributes的参数有两种:
一种是String类型,表示在存值过程中,key值与当前string值相同,则同时将数据存入到session中
另一种是class类型,里面写类的class对象,如果存入的值是改对象类型,则同时保存入session
@sessionAttributes(value=“user1,user2,user3”)
括号内可以放多个,用逗号隔开
在注解中声明对象类型,则如果存入request域中的对象是该类型,则同时放入session
@sessionAttributes(types=User.class)
也可以写多个:@sessionAttributes(types={User.class,Student.class,…})
@ModelAttribute注解
该注解一般有两种作用,一种加在方法上,另一种加载参数前
1.加在方法上
在不改变原方法,还想增加新功能时使用
此注解加在方法上,此时就表示在执行任何一次请求前,都会先执行@ModelAttribute修饰的方法
//在前台访问test时,会首先执行有该注解的方法,然后再执行test方法
@ModelAttribute
public void md(Model model) {
User user = new User();
model.addAttribute("user", user);
//这里会将user给下面test方法的参数中User赋值
}
//他表示将上面的user对象传入下面方法的参数中
//但是需要注意的是,上面model存值的key,只能是类名的首字母小写形势,不然无法正确传值
//如果不是这个格式,需要在方法中参数前加@modelAttribue注解指定
@RequestMapping("/test")
public String test(@ModelAttribute("user")User user) {
return "success";
}
2.加在参数前
当该注解加在参数前时,会自动将后面的参数存入到request作用域中,
当作一个前台的对象模型使用,一般情况下,如果需要后台使用mvc表单,则需要传入该模型对象,
以供后台进行识别,有针对性的建立表单
我们在controller中的返回值,无论是String,ModelAndView,或者是View,最终,统一都会变为ModelAndView类型,这样才能被试图解析器去解析,然后返回到前台,可以是jsp/html/excel等等
视图的顶级接口:View
视图解析器的顶级接口ViewResolver
常用的视图
常见的视图解析器:
InternalResourceViewResolver也是我们最常使用的视图解析器,在SpringMVC配置文件中配置
配置方式:
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置前缀 -->
<property name="prefix" value="/views/"></property>
<!-- 配置后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
不同的解析器可以解析不同的文件,如果需要解析不同类型,就应该去根据需求配置不同的解析器,jsp的解析器是我们最常用的,它的作用就是解析jsp视图
JstlView是InternalResourceView的子类, 可以实现国际化操作,他可以解析jstl
但我们并不需要单独去配置他,springMVC解析jsp时,默认会使用父类InternalResourceView,但如果发现jsp中包含了jstl语言,则自动转为子类JstlView去解析
所谓的国际化,实际指的是针对不同的国家,显示不同的内容
具体的实现步骤如下:
1.创建资源文件:
资源文件就是国际化实现时,针对不同的国家,去资源文件中寻找不同的语言结果
常见的资源文件命名方式:
基名_en.properties 针对于所有英文语言的资源
基名_en_US.properties 针对于美国地区的语言
基名_zh_cn.properties 针对于中国地区的语言
类似的名称还有很多很多,自行去百度查找名称。。。。
这种命名方式一般是:基名_语言_国家.properties
如果遇到一些资源文件中没有的值,则去最大的通用文件中去找
范例:
i18n.properties 主文件,如果下面资源文件中都没有的值,则去该文件寻找
i18n_zh_CN.properties 中国大陆文件
i18n_en_US.properties 美国大陆文件
i18n_zh_HK.properties 中国香港文件
2.配置国际化的bean
springMVC在启动时,会自动寻找一个id=“messageSource”的bean,如果有,则自动加载,所以需要配置id值
配置类文件,加载资源文件方式:
他就会寻找所有的对应的i18n文件,没有指定语言和地区的i18n.properties则是缺省值
3.通过jstl标签实现国际化
Jstl两个jar包,jstl.jar,standard.jar
页面中导入fmt包
页面中编写:
Key为properties文件中的key
此时,针对于不同的国家,他就会寻找不同的资源文件,找到对应的值,然后进行显示
国际化必须通过xml中配置的解析器进行解析,跳转页面才可以实现,直接访问是不可以的
因为ResourceBundleMessageSource在MVC响应的时候才会介入,查找国际化文件
国际的化的测试依赖于浏览器的语言,当你把语言改为其他国家语言时,对应的也就会发生改变
在进行访问时,有时候我们不需要进行任何的操作,只想要从一个页面跳转到另一个页面
这时候可以用到mvc的一个配置,在xml配置文件中配置
Mvc同样会给他加前缀和后缀
此时Jsp页面访问view/test请求时,会通过配置文件中的配置直接跳转到success.jsp页面(需要加前缀和后缀)
但有了这个配置之后,mvc默认会对所有的请求都去xml配置文件中寻找,因此相当于屏蔽了controller,如果想要二者共存,就需要加入一个配置:
这个配置是协调作用,能够让许多功能共存,他是基本配置,一般我们为了保证所有功能共存,都会添加该注解
重定向:
Springmvc默认视图的跳转方式是请求转发,就是地址栏里的请求还是指向@requsetmapping,但实际跳转的页面却是成功之后的界面,
如果想要实现重定向,只需要在返回页面的值时加入
Redirect: 即可
@requsetMapping(“test”)
Public String test (){
return “redirect:success.jsp”;
}
//请求转发是:forword: 但他是默认值,一般我们不需要加他
//需要注意的是,如果使用这个前缀,则视图解析器不会给你拼接前缀与后缀,
//需要自己手动去写,如果不写,他默认会访问success路径,因此还可以实现方法之间的跳转
在SpringMVC中,如果直接访问静态资源,会出现404(找不到资源)
原因是:
默认拦截了一切请求,他会把所有的请求都去核心控制器去寻找
解决方式:如果需要SpringMVC处理的,则交给mvc,如果不需要,则对资源进行放行操作,
使用tomcat默认servlet处理(如果有默认servlet,则去servlet处理,否则就直接访问)
处理方式:
该注解会在SpringMVC接收到一个请求,并且mvc中没有该请求映射时,会自动将该请求交给tomcat默认servlet处理,(直接访问)
但是一般情况下,这些注解都需要依赖annotation-driven才可以使用,所以上文说基本上任何情况下都需要加这个配置
转换器的作用主要是将前台传给后台的数据进行按条件转换,例如:前台传入:张三-男-18,通过转换器对字符串进行处理,将结果转换为对象等等操作
Spring自带一些常见的类型转换器,
在前台向后台传递数据时,例如前台传id=1,后台接收无论int,Integer,或者string均可接收到值,
但对于一些特定要求的值,我们就需要自己定义转换器
public class MyConverter implements Converter<String , Book>{
//实现Converter接口,泛型的值指的是:<传入的数据,转换的数据>,此处
//表示传入一个字符串,转换为book对象
@Override
public Book convert(String source) {
// 在这里只需要进行正常的转换步骤即可,例如将字符串切割,并转换为对象
Book book = new Book();
return book;
}
}
2.将编写的转换器加入到mvc中
将自定义转换器纳入SpringIOC容器管理
在SpringMVC中配置一个bean
<bean id=”myConverter” class=”com.dcz.util.MyConverter”></bean>
将配置的bean纳入到SpringMvc提供的转换器bean
<bean id=”conversionService” class=””org.springframework.context.support.ConversionServiceFactoryBean>
<property name=”converters”>
<set>
<ref bean=”myConverter”>
</set>
</property>
</bean>
Springmvc提供的转换器类中存储转换器的类型是set集合
将注册好的Spring转换器注册到annotation-driven中
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
测试:
在参数前加@requestParam(“mesage”)
当前台传入的请求中有message=”zs-18-男”时候,就会执行转换器
@requestParam(“mesage”)他接收到的是字符串,但他修饰的是对象,满足这两个条件就会触发转换器
SpringMVC提供了许多注解,方便我们对数据进行格式化
实现步骤:
1. Xml配置:
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean>
//配置数据格式化所依赖的bean
2.通过注解来使用
例如日期使用:@DateTimeFormat(partten=”yy-MM-dd”) 加在实体类Date类型前
此时,前台传入字符串为“2001-01-01” 但后台属性为Date类型,也能正确接收到
前台向后台传递格式化数据时,如果传递错误,student无法正确接收,会将错误信息
自动传递给加在Student参数后面的Bindresult
@RequestMapping("/test")
public String test(Student student,BindingResult result) {
//bindingResult就用于接收错误信息,如果没有这个参数,出错时,前台页面立马报错
return "success";
}
如果后台有BindResult 则前台就不会报错,相当于后台进行了try…catch
注意:Student和错误信息BindResult位置不能变换错误信息只能在第二个位置,因为BindResult的作用是保存它前一个数据的错误信息
数字格式化:
@NumberFormat(partten = “###,#”)
此时,前台传入的值必须是三个数字一个逗号在加一个数字(111,1)逗号只是占位符,实际值还是1111
FormattingConversionServiceFactoryBean
这个类既可以实现上述两个格式化,他同时也是配置自定义类型转换的bean,
以后我们配置类型转换的时候就可以直接配置这个bean,同时相当于拥有了两个功能
JSR-303以及Hibernate-Validator两种常用方式,后者是前者的补充,功能更全面
步骤
1. 导入jar包
2. 配置
/**在springmvc框架中实现各种校验,必须实现一个接口:ValidatorFactory
但Spring已经进行了实现LocalValidatorFactoryBean是ValidatorFactory的一个
实现类而配置annotation-driven就是把这个实现类自动给你配置进去 */
3.直接在实体类中加入注解,并在需要校验的controller中加入注解@valid
@RequestMapping("/test")
public String test(@Valid Student student,BindingResult result) {
//需要校验Student则在前面加入@valid注解,在后面写bindingResult收集错误信息
return "success";
}
在需要验证的类中加各种验证注解
public class Student {
@NotNull
@Size(max = 5,min = 2)
private Integer id;
@NotBlank
private String name;
@Future
private Date birthday;
}
SpringMVC会自动将数据的错误信息存入BindingResult 我们只需要获取里面的值,即可接受到错误的信息,
NotNull和NotBlank的区别:
String name = null;
@NotNull: false
@NotEmpty: false
@NotBlank: false
String name = "";
@NotNull: true
@NotEmpty: false
@NotBlank: false
String name = " ";
@NotNull: true
@NotEmpty: true
@NotBlank: false
String name = "Great answer!";
@NotNull: true
@NotEmpty: true
@NotBlank: true
Ajax请求时,因为是同页面,不需要前往新的页面,所以只返回数据即可,
前台直接返回对象或者集合,只需要在方法上加@responseBody,springMVC即可自动给你转换为JSON
对象,前台ajax接收到之后,可以直接进行使用,不需要任何操作
前台接受到的数据是json数组的形式
后台直接返回集合、对象、数组等等即可、不需要tojsonString等等任何操作
@RequestMapping("/test")
@ResponseBody
public List<User> test() {
List<User> list = new ArrayList<User>();
return list;
}
需要导入的包:
Commons-fileupload.jar
Commons-io.jar
springMVC可以简化文件上传的代码,但需要实现MultipartResolver接口,但MVC已经给我们提供了其对应的实现类:CommonsMultipartResolver
具体步骤:
配置xml文件,将CommonsMultipartResolver加入配置文件
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"></property>
</bean>
//需要注意的是,id的值不能变,改变之后spring无法识别
前台使用表单进行上传,要求请求方式必须是post , 必须加这个属性:enctype=”multipart/form-data”
后台接收时,可直接用MultipartFile 进行接收,然后对这个对象进行具体操作即可,操作如下:
MultipartFile类中常用方法 | 方法描述 |
---|---|
getOriginalFilename() | 获取对应的文件名称(包含后缀) |
getInputStream() | 获取对应的流对象,然后即可读取文件中内容,一般用于读取后直接写到服务器中 |
transferTo(File file) | 将文件内容写入到指定的文件中 |
可以对请求进行拦截,拦截的位置为请求之前,请求之后,以及请求完成
1. 编写拦截器类,实现HandlerInterceptor接口
2. 重写其三个方法
preHandle:客户端请求服务器时拦截
postHandle:服务器处理完请求,响应给客户端时拦截
afterCompletion:页面渲染完毕之后拦截
三个方法的返回值均为boolean类型,true则表示放行,false表示拦截
3. 将拦截器配置到springmvc中:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" /> //表示拦截一切请求
<mvc:exclude-mapping path="/login" /> //表示该请求不拦截
<mvc:exclude-mapping path="/checkName" />
<bean class="com.test.utils.MyInterceptor"></bean> //拦截器的bean
</mvc:interceptor>
</mvc:interceptors>
如果配置多个拦截器,preHandle方法按照配置的顺序执行,postHandle按照相反的顺序执行,afterCompletion也按照相反顺序执行。
Springmvc处理异常,必须实现顶级接口HandlerExceptionResolver
该接口的每个实现类,都是一种异常的处理方式
ExceptionHandlerExceptionResolver:主要提供了@ExceptionHandler注解,并通过该注解处理异常
@ExceptionHandler(RuntimeException.class)
public String runtime(RuntimeException e) {
//这里表示出现runtime异常时,会执行这个方法
return "error";
}
参数中的e 就相当于是catch块括号中捕获的异常,当捕获到异常时,就会走这个方法,
注意:异常方法参数括号中只能有一个异常的对象,不能包含其他对象,否则就会失效!!!
如果有多个异常方法都符合条件,则按照那个就近原则,有异常类就去找本身,没有对应的异常就去找齐父类,依次往上找
异常方法只能捕获当前类出现的异常,对于其他controller类的异常无法捕获
如果需要单独定义一个类,用于专业处理各个controller类中的异常
则可以在类上使用@ControllerAdvice他就表示我是专业处理异常的类,可以处理所有controller类中的异常
@ControllerAdvice
public class DisposeControllerException {
/**
* 这是一个专业处理异常的类
* VerifyUserException 是自定义的一个异常
* 方法参数中只能包含异常的对象
* 我们在这里对异常进行处理
*/
@ExceptionHandler(VerifyUserException.class)
public ModelAndView loginException(VerifyUserException e) {
String message = "异常啦!!";
ModelAndView mv = new ModelAndView("error");
mv.addObject("message", message);
return mv;
}
}
2.异常状态提示
ResponseStatusExceptionResolver类
他可以自定义用户页面异常显示的状态,以及文字
提供了注解@ResponseStatus
将注解加在自定义的异常类上面(注意:自定义异常需要继承Exception或者其子类)
如果有方法抛出了该自定义异常,则页面就显示此错误
这个注解有两个参数:
value:表示前面状态码,例如404, 有一个枚举类为他提供常用状态码: HttpStatus类
reason:表示异常的表述信息,即下图中message的内容,例如:SpringMVCProject/abcdefg.jsp
@ResponseStatus(value= 枚举,reason = “错误”)
@requestMapping(“test”)
Public void test(){
//此时如果访问test,则会出现此异常
}
总结:@ExceptionHandler是用来处理异常的,可以加在方法上
如果需要单独定义一个异常处理类,则需要在类上加@controllerAdvice
然后正常定义方法并加注解@ExceptionHandler
@ResponseStatus是用来定义异常的,他可以定义用户页面的异常显示信息,
可以加在方法上(如果前台访问该方法则异常),也可以加在自定义异常类上(若抛出该异常则出现异常)
最后,需要注意的是,如果使用@ResponseStatus定义了异常,但@ExceptionHandler处理了该异常,则页面不会显示错误