SpringMVC介绍之约定优于配置
所谓的约定优于配置就是指在程序开发过程中我们约定好一些规则可以使我们更少的进行配置和代码编写。就这么简单的一句话可能你还不是很懂什么是约定优于配置,没关系,看完后面对SpringMVC的约定优于配置的介绍之后你就会明白了。
SpringMVC对约定优于配置的支持主要表现在三个方面,Model、View和Controller。
Model:SpringMVC对Model的约定优于配置的支持是基于ModelMap的,由于ModelAndView中的Model就是一个ModelMap,所以ModelAndView也是支持的。约定优于配置在Model上的表现是通过ModelMap的addObject方法实现的,当我们需要往ModelMap中添加一个对象的时候,我们可以只添加一个对象,而不指定其对应的属性名称,即调用addObject(Object obj)方法,而不是调用addObject(String attrName, Object obj)方法。这个时候Spring就会根据它自身约定的一套机制给我们一个默认的属性名称。Spring的约定是这样的:
(1)采用这种方式添加的对象不能为null,所以如果添加的对象有可能为null时就不应该使用这种方式,还是使用addObject(String attrName,Object obj)方法指定一个属性名称比较好。
(2)采用这种方式添加的集合Collection不能为empty,同样如果该Collection有可能为empty的时候就不应该使用这种方式。
(3)简单对象,当是一个简单对象的时候取该对象的类名称,不包括包名,然后采用JavaBean的属性命名规则来确定属性名称,如添加com.host.app.model.User对象时取的属性名称就是user,添加com.host.app.model.HelloWorld对象时取的属性名称就是helloWorld,添加com.host.app.model.ABCdef对象时取的属性名称就是ABCdef。
(4)数组,当添加的是一个数组的时候,Spring会取该数组的类型按照规则3取到一个名称作为基名称,之后再加上List后缀作为约定的属性名称。如添加一个Object数组时,Spring约定的属性名称就是objectList,添加一个com.host.app.model.ABCdef数组时,Spring取的属性名称就是ABCdefList。
(5)集合Collection,当添加的是一个集合的时候,Spring会采用Iterator的方式取该集合的第一个元素类型按照规则3取到一个名称作为基名称,之后再加上List后缀作为约定的名称。如添加一个List时,如果取出的该List的第一个元素是java.lang.Object对象,那么Spring取的属性名称就是objectList;添加一个包含的都是com.host.app.model.User的Set时,Spring取的属性名称就是userList;如果添加的HashSet中同时包含多种类型的对象时就应该使用addObject(String attrName, Object obj)方法指定自己的属性名称,因为HashSet内部的元素是无序的,每次取的第一个元素可能不一样,这也就会导致Spring取的属性名称会不一样。
看下面一个示例,当我们访问控制器处理方法testModel时,往返回的模型中添加了一个包含User的List对象,这样在ModelAndView内部内置的ModelMap中就会采用约定好的方式取userList为该对象在模型中的属性名称。
- public ModelAndView testModel() {
- ModelAndView mav = new ModelAndView("modelTest");
- User user = new User(1, "zhangsan");
- List<User> list = new ArrayList<User>();
- list.add(user);
- mav.addObject(list);
- return mav;
- }
View:当Controller处理器方法没有返回一个View对象或逻辑视图名称,并且在该方法中没有直接往response的输出流里面写数据的时候,Spring就会采用约定好的方式提供一个逻辑视图名称。这个逻辑视图名称是通过Spring定义的org.springframework.web.servlet.RequestToViewNameTranslator接口的getViewName方法来实现的,我们可以实现自己的RequestToViewNameTranslator接口来约定好没有返回视图名称的时候如何确定视图名称。Spring已经给我们提供了一个它自己的实现,那就是org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator。
在介绍DefaultRequestToViewNameTranslator是如何约定视图名称之前我们先来看一下它支持用户定义的属性:
(1)prefix:前缀,表示约定好的视图名称需要加上的前缀,默认是空串。
(2)suffix:后缀,表示约定好的视图名称需要加上的后缀,默认是空串。
(3)separator:分隔符,默认是斜杠“/”。
(4)stripLeadingSlash:如果首字符是分隔符,是否要去除,默认是true。
(5)stripTrailingSlash:如果最后一个字符是分隔符,是否要去除,默认是true。
(6)stripExtension:如果请求路径包含扩展名是否要去除,默认是true。
(7)urlDecode:是否需要对URL解码,默认是true。它会采用request指定的编码或者ISO-8859-1编码对URL进行解码。
当我们没有在SpringMVC的配置文件中手动的定义一个名为viewNameTranlator的bean的时候,Spring就会为我们提供一个默认的viewNameTranslator,即DefaultRequestToViewNameTranslator。
接下来看一下,当Controller处理器方法没有返回逻辑视图名称的时候,DefaultRequestToViewNameTranslator是如何约定视图名称的。DefaultRequestToViewNameTranslator会获取到请求的URI,然后根据提供的属性做一些改造,把改造之后的结果作为视图名称返回。我们以请求路径http://localhost/app/product/index.html为例来说明DefaultRequestToViewNameTranslator是如何工作的。该请求路径对应的请求URI为/product/index.html,我们来看以下几种情况,它分别对应的逻辑视图名称是什么。
(1)prefix和suffix都存在,其他为默认值是对应返回的逻辑视图名称应该是prefixproduct/indexsuffix。
(2)stripLeadingSlash和stripExtension都为false,其他默认,这时候对应的逻辑视图名称是/product/index.html。
(3)都采用默认配置时,返回的逻辑视图名称应该是product/index。
如果我们的逻辑视图名称都跟请求路径相同或者相关关系是一样的,我们就可以采用Spring为我们事先约定好的逻辑视图名称返回,这可以大大简化我们的开发工作。
下面是一个在SpringMVC配置文件中配置一个RequestToViewNameTranslator bean的示例。记住,该bean的名称只能为viewNameTranslator,如果不为viewNameTranslator时,Spring还是会使用默认配置的DefaultRequestToViewNameTranslator来约定逻辑视图名称。
- <bean id="viewNameTranslator" class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator">
- <property name="prefix" value="prefix"/>
- <property name="suffix" value="suffix"/>
- <property name="stripLeadingSlash" value="false"/>
- <property name="stripExtension" value="false"/>
- </bean>
Controller:此处讲SpringMVC对约定优于配置的支持是基于注解配置Controller的情况。考虑这样一种情况:定义了一个Controller,名为MyController,然后在MyController类上使用了@Controller注解进行标记,没有类级别的@RequestMapping。MyController中定义了一个处理器方法add,该方法使用了@RequestMapping注解标记。大概就是下面这个样子。
- @Controller
- public class MyController {
- @RequestMapping("add")
- public String add() {
- return "add";
- }
- }
这个时候如果我们需要访问到处理器方法add的话,我们需要请求/add.do,然后有另外一个AnotherController,里面也有一个add方法对应/add.do请求,这个时候如果你再请求/add.do的时候Spring就不知道到底该访问那个方法,然后就会抛出异常,这个时候我们最简单的解决办法就是在MyController上加上类级别的@RequestMapping用以区别,表示请求的路径到底是哪个Controller下面的,类似的情况还有我们会把相关的处理器方法放在一个Controller中,比如UserController下面会有user的add方法,user的del方法等。Spring为我们提供了一种机制可以自动根据我们的Controller类名称来进行请求映射,这是通过在SpringMVC的配置文件中定义一个org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping bean来实现的。通过它的名称我们可以知道ControllerClassNameHandlerMapping就是通过Controller的类名称来进行类级别的请求映射的。使用ControllerClassNameHandlerMapping的默认属性配置的时候Spring是这样来进行请求映射的:
(1)首先取得去掉包名称的Controller类名称。
(2)如果该类名称是以Controller结尾,则只取Controller前面的部分,如MyController取My。
(3)将取到的名称取全部小写,如MyHome取myhome。
(4)然后将上面取到的名称映射为/name/*,如上面取到的名称是myhome,则映射为/myhome/*。
- @Controller
- public class MyController {
- @RequestMapping("add")
- public String add() {
- return "add";
- }
- }
还是这一段代码,当我们使用ControllerClassNameHandlerMapping来进行映射的时候,我们需要访问MyController的处理器方法add的时候就需要请求/my/add.do。
ControllerClassNameHandlerMapping支持用户定义如下属性:
(1)caseSensitive:大小写是否敏感,默认是false,该属性主要是用来生成映射路径的时候匹配大小写是否敏感,如果为true,则只把Controller类名称的首字母小写,其他的保持原样进行请求路径映射,如果为false,则全部小写。basePackage也使用同样的规则,只是basePackage在caseSensitive为true的时候不需要首字母小写。
(2)basePackage:表示要用于生成路径映射的基包,默认是null,这个时候就采用Controller不包含包名称的类名称来映射,映射规则跟之前介绍的映射规则相同。如果定义了basePackage,假设为com.host.app,这个时候如果Controller类的全名称是com.host.app.abc.edf.MyController,那么映射的路径就是/abc/edf/my/*。
(3)pathPrefix:表示映射路径的前缀,默认是空串。假设pathPrefix为prefix,basePackage为com.host.app,那么com.host.app.abc.MyController的映射路径就是/prefix/abc/my/*。
(4)excludedPackages:是数组形式,表示需要把哪些包排除在ControllerClassNameHandlerMapping的映射范围之内。
(5)excludedClasses:是数组形式,表示需要把哪些类排除在ControllerClassNameHandlerMapping的映射范围之内。
在下面一个例子就排除了com.host.app.web.mymodule包、com.host.app.web.modulea.MyController和com.host.app.web.moduleb.UserController。
- <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
- <property name="order" value="1"/>
- <property name="excludedPackages">
- <array>
- <value>com.host.app.web.mymodule </value>
- </array>
- </property>
- <property name="excludedClasses">
- <array>
- <value>com.host.app.web.modulea.MyController</value>
- <value>com.host.app.web.moduleb.UserController</value>
- </array>
- </property>
- </bean>
使用ControllerClassNameHandlerMapping需要注意的地方:
(1)需要使用ControllerClassNameHandlerMapping来映射的Controller类上如果加了@RequestMapping注解ControllerClassNameHandlerMapping也是可以进行URL路径映射的。
(2)使用ControllerClassNameHandlerMapping映射的是类似于/controllerName/*这样的形式,这也就是说只有在处理器方法映射不存在斜杠的时候才可以使用这种形式访问到。看下面一个例子,在下面代码中MyController类能够映射的请求路径是/my/*,这也意味着只有满足/my/*的请求路径才能映射到MyController,才能访问到它里面的处理器方法,所以当请求/my/test1.do的时候毫无疑问可以访问到处理器方法test1,但是当想访问MyController的test2方法,请求/my/test/test2.do的时候由于它不能映射到MyController,所以不能如愿的访问到MyController的test2方法。这也是ControllerClassNameHandlerMapping 一个缺陷。
- @Controller
- public class MyController {
- @RequestMapping("test1")
- public String test1() {
- return "test";
- }
- @RequestMapping("test/test2")
- public String test2() {
- return "test";
- }
- }
(3)由于在SpringMVC应用中可以同时定义多个HandlerMapping,这就涉及到一个映射的优先级问题。HandlerMapping都实现了Ordered接口,所以我们可以通过HandlerMapping的order属性来指定匹配映射的先后顺序。我们知道在ViewResolver链中,如果一个逻辑视图被一个ViewResolver解析了之后,该次视图解析就结束了,其他的视图解析器就不能再解析这个视图了,它的order属性是用来定义ViewResolver进行视图解析的先后顺序的。但是HandlerMapping不一样,它是在SpringMVC的配置文件中定义的所有的HandlerMapping都可以进行URL映射,它的order属性是用于指定映射匹配的先后顺序的。看一个例子:
- <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
- <property name="order" value="1"/>
- </bean>
- <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
- <property name="order" value="10"/>
- </bean>
我们在SpringMVC的配置文件里面定义了两个HandlerMapping,代码如上所示,由它们的order属性我们知道ControllerClassNameHandlerMapping会先于DefaultAnnotationHandlerMapping进行映射匹配。定义了一个MyTestController,代码如下所示:
- @Controller
- public class MyTestController {
- @RequestMapping("mytest/test")
- public void test() {
- System.out.println("--------hello test---------");
- }
- @RequestMapping("test")
- public void test2() {
- System.out.println("--------hello test2---------");
- }
- }
我们知道ControllerClassNameHandlerMapping会把MyTestController映射为“/mytest/*”,按照这种方式我们只能利用/mytest/test.do请求到MyTestController的test2方法,而没法利用/mytest/mytest/test.do请求到test方法。而DefaultAnnotationHandlerMapping会把MyTestController的test2方法映射为“/test.do”,把test方法映射为“/mytest/test.do”。而根据Spring定义了多个HandlerMapping就会有多个映射机制存在的这么一个机制我们知道上述几种映射关系都是会存在的。那么这个时候如果我请求/mytest/test.do会请求哪个方法呢?我们知道,如果是按照ControllerClassNameHandlerMapping的映射机制会访问MyTestController的test2方法,而按照DefaultAnnotationHandlerMapping的映射机制就会访问MyTestController的test方法。这个时候HandlerMapping的order属性就起作用了,order属性越小的就会先匹配,由上面的配置我们知道ControllerClassNameHandlerMapping的order属性相对较小,所以将使用它的映射URL来匹配这次请求,所以处理的是MyTestController的test2方法。
仁者见仁智者见智吧,繁琐的配置文件我觉得更麻烦
繁琐的配置文件如果组织好,是不麻烦的。如果用annotation的话,配置文件也可以减重很多。
其实配置文件就应该如同编写代码一样,归类到相应的目录或者遵循一定的命名规范,自解释的话,维护起来会很轻松。
仁者见仁智者见智吧,繁琐的配置文件我觉得更麻烦
相关推荐
1. **约定优于配置**:遵循一定的命名规范和目录结构,提高代码可读性和团队协作效率。 2. **单元测试**:为关键业务逻辑编写单元测试,确保代码质量。 3. **异常处理**:对可能出现的异常进行捕获和处理,避免系统...
本章可能涉及SpringMVC的“约定优于配置”原则,这是一种简化开发的方法,通过预设的规则减少显式的配置。例如,通过使用@Controllers和资源目录的约定,可以更轻松地管理控制器和静态资源。 这份教学文档全面覆盖...
1. **项目结构**:Maven遵循约定优于配置的原则,标准的目录结构包括`src/main/java`(源代码)、`src/main/resources`(资源文件)、`src/test/java`(测试代码)等,这简化了项目配置。 2. **依赖管理**:通过在`...
SpringMVC更加强调约定优于配置的原则,使得开发效率更高。 - **Spring vs SpringMVC**:Spring是一个更大的框架体系,包含了SpringMVC在内的多个子项目。SpringMVC是Spring框架中的一个子项目,专门用于Web应用的...
2. 更好的架构设计,如约定优于配置。 3. 简洁的Web层开发,支持RESTful风格。 4. 与Spring框架其他组件深度集成。 5. 强大的数据绑定和验证机制。 总结,SpringMVC作为现代Web应用开发的主流框架之一,以其高效、...
4. **Maven项目结构**: Maven遵循约定优于配置的原则,标准的项目结构包括`src/main/java`存放Java源代码,`src/main/resources`放资源配置文件,`pom.xml`是项目对象模型,描述项目信息和依赖关系。 **二、...
SpringMVC是Java后端开发领域中常用的Web层框架之一,属于SSM(Spring、...SpringMVC通过其提供的各种功能组件和约定优于配置的设计理念,为开发者提供了一个强大且灵活的Web开发框架,大大简化了Java Web应用的开发。
而 Struts2 更注重约定优于配置,配置相对较少,但可能在复杂应用中显得不够灵活。 总的来说,Spring MVC 是一个强大且灵活的 Web 开发框架,它的核心组件和工作流程对于理解并有效利用该框架至关重要。通过熟练...
它有一套约定优于配置的原则,使得项目结构更加规范,减少了初始化项目的复杂性。 **Maven的使用** 在"Maven SpringMVC mybatis例子"中,Maven主要负责管理项目的依赖。开发者只需要在POM.xml文件中声明所需的依赖...
MVC框架和流程处理描述了Model、View、Controller三者如何协同工作,SpringMVC通过约定优于配置的方式简化了传统MVC的配置工作。 前台数据传递主要涉及将数据从视图页面传递到控制器的方案,比如通过表单提交、URL...
21. "约定优于配置"的支持 这部分会介绍Spring如何通过约定来减少配置的数量,以及如何使用ModelMap或ModelAndView来传递模型数据。 22. HTTP缓存支持 HTTP缓存可以提升Web应用的性能。文档中会讨论如何使用Cache-...
3. **标准化**: 通过约定优于配置的原则,简化项目配置。 4. **插件丰富**: 提供大量插件,满足不同需求,如代码质量检查、性能测试等。 ### Maven与SpringMVC项目设置 1. **创建项目**: 使用Maven的`mvn ...
- **知识点**:Maven约定优于配置的原则,这些文件夹的作用及其在构建过程中的作用。 - **更改类路径**:在Java Build Path中设置源文件夹的输出目录。 - **知识点**:输出目录(target/classes等)的用途,以及...
- SpringBoot的核心理念是“约定优于配置”,它通过自动配置和起步依赖简化了项目的创建和配置。 - 内置Tomcat服务器,使得我们可以快速启动并运行一个Web应用。 - 提供命令行接口(CLI)和starter POMs,方便...
Maven使用约定优于配置的原则,简化了项目设置。 4. **Spring MVC**:Spring框架是Java企业级应用开发的事实标准。Spring MVC是其Web模块,提供了模型-视图-控制器(MVC)架构,用于构建可测试、松耦合的Web应用。...
Maven 使用约定优于配置的原则,简化了构建过程,并通过中央仓库管理依赖关系,使得项目构建和依赖管理变得标准化。 整合这些组件,我们可以创建一个高效的开发环境: - 首先,通过Maven的POM.xml文件定义项目依赖...
Maven使用约定优于配置的原则,大大简化了项目构建过程,减少了开发者的工作量。 **二、SpringMVC框架** SpringMVC是Spring框架的一个模块,用于处理HTTP请求。它遵循Model-View-Controller设计模式,帮助开发者...
它通过“约定优于配置”的原则,内置了Tomcat服务器和自动配置功能,使得开发者无需过多关注繁琐的配置,可以更专注于业务逻辑。 二、SpringMVC概述 SpringMVC是Spring框架的一部分,是一个基于模型-视图-控制器...
它的核心理念是“约定优于配置”,使得开发者能快速创建独立运行的、生产级别的Spring应用。SpringBoot自动配置了大量常见的Spring组件,如数据源、JPA、Thymeleaf等。在源码分析中,我们可以看到如何通过@...
SpringBoot推崇“约定优于配置”的原则,大大减少了常规的XML配置,使得开发更高效。此外,它内置了Tomcat服务器,支持微服务、RESTful API设计,以及健康检查、监控等功能。 在学习这三者的过程中,你将掌握如何...