spring4 mvc 快速入门 - spring boot or not?
来源:互联网 发布:淘宝为什么让马云有钱 编辑:程序博客网 时间:2024/05/16 15:46
spring mvc 简洁易学。但自从 spring 4 开始,案例都采用 spring boot,无论老鸟菜鸟都懵了啊。本文介绍 mvc 的框架原理,使用简单案例分别使用spring boot 容器、其他 servlet 容器(jetty)的xml配置、无 xml 配置实现,讨论 spring4 mvc 不同环境实现程序之间的区别和联系。由于每种方式不是代码兼容的(蛋疼),这对 servlet 程序员来说是痛苦的负担,两套体系的挣扎。但对于新人,则可以选择自己喜欢的方式快速实现 web mvc 编程。
一、 MVC 的概念
1. 什么是 MVC
MVC是一种结构风格,就是将程序的输入、处理、输出这个顺序过程抽象为模型、视图、控制三个部分。程序员仅需关注业务的数据、展现、流程三个元素,将 Context,通讯协议、进程与线程、会话等复杂的要素交给框架处理,实现业务为中心的编程理念。在 web 应用中,MVC的含义是:
- M(模型/Model):业务涉及的数据对象实例。例如,你显示一定订单,它包含用户、订单、订单项、支付等业务对象数据;
- V(视图/View):展示业务人机交互界面的显示模板。例如,jsp 文件等,它能将模型中的数据填入显示模板,用户可看到界面元素丰富的界面;
- C(控制器/Controller):用户输入处理单元。它检查输入的合法性,处理输入表单,按流程调用业务函数,生成输出需要的数据模型,选择视图模板,输出。
使用MVC结构编程,使得程序业务逻辑清晰,模块结构好。对提升开发效率,增强可维护性,促进团队内部按技能分工,起到关键作用,因此几乎所有语言都有自己若干不同的 MVC 支持框架实现。
2. MVC 在 web 程序中的位置
对于新手,常会对某种语言或 MVC 框架产生崇拜,例如学了 MVC 就掌握了 web 编程,喜欢对比 struts 和 spring mvc 的效率。本节的目的是供新手了解 MVC 结构在 web 程序中的位置。附图表示了 MVC 结构在 web 开发中的位置。
无论是 J2EE 或 轻量级 web 应用,大概分为三个层次:
- 表示层(present layer): 处理 HTTP 输入(Request),然后调用业务服务,产生输出(Response)。这里,应用开发人员只需要考虑 MVC 三个编程元素。
- 业务层(business layer): 提供满足 ACID 要求的业务服务。这里,开发人员只需声明对外的业务服务函数,spring 等提供事务(Transaction)支持。
- 持久化层(persistence layer):提供数据表存取机制,主要是 ORM 框架实现以对象-关系数据库的映射。这里,开发人员只需声明表和对象的映射,特殊的 SQL。
因此,MVC结构仅是 web 开发中表示层技术。
JAVA 所有框架都尊崇这样的理念,“应用开发人员关注于业务逻辑的实现而不是底层的实现机制”。JAVA 开发一般是最佳实践驱动,即文件名、类名、目录结构、包结构都有自己一套长期形成的默认规则,这是初学者最大的学习障碍(demo 程序不一定遵守这些规则)。最佳的办法就是在看靠谱的项目代码,学习 Java 设计模式。例如:一个类中出现 process(...) 方法,你立马就知道这时命令模式(command pattern)的实现,必定实现了一个 xxxCommand 接口。
3. MVC 部件执行过程
各种语言 web MVC 框架不可胜数,但执行过程都是一致的。
- 分配/映射:这时框架完成的,它根据客户端 URL 映射到你定义的控制器类(使用 @ 或 外部 xml),做部分 Valid 检查
- 控制器:执行业务流程,一般步骤是:
- 参数检查
- 业务服务访问
- 装配数据模型
- 选择输出模板
- 模板渲染:模板按数据模型提供的数据渲染,生成网页或特定数据格式
因此,你需要一些 HTTP 基础知识;URL 到函数的映射;模板渲染表达式。
4. 选择 MVC 框架
尽管 spring MVC 的效率是一直被质疑,反射用的越多的框架效率也差一些,但使用会更方便。
选择 MVC 框架第一准则是团队培训成本,即你团队最优秀的人会什么,大家都用什么。第二准则是简单实用,简单实用是相对感受=没标准,个人喜欢 HTTP Request 与 处理函数的 Mapping 模型(如 spring MVC),这与 Restful Service 开发泛型是一致的,是现代 web 开发最流行的方式。
二、用 spring boot 实现 spring4 mvc
这里使用的 Spring 官方案例,参见:http://spring.io/guides/gs/serving-web-content/ 。可直接从 GIT 下载代码。
开发环境 JAVA JDK 1.8, Maven 3.3 +。 如果你使用 Centos 7,可参见:http://blog.csdn.net/pmlpml/article/details/53427164
1. 程序结构
对于刚学 Java 的来说,这与普通 Java 程序几乎没有区别。程序在 /src/main/java 源代码目录下;静态资源与视图模板都 /src/main/resources 目录下;maven 文件 pom.xml。
2. 控制器与模型
@Controllerpublic class GreetingController { @RequestMapping("/greeting") public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model) { model.addAttribute("name", name); return "greeting"; }}
GreetingController 代码非常简单,要点:
- @Controller 注释申明这个类是控制器
- @RequestMapping("/greeting") 注释申明 URL 匹配 “/greeting” 给这个函数处理。
- @RequestParam(value="name", required=false, defaultValue="World") 注释申明如果查询字符串中有 name=value 则 value 转为 String 给 name 这个参数。例如:URL 是 /greeting?name=User 则变量 name = “User” 。
- model 是一个容器,存放变量供视图模板使用
- 返回 “greeting” 是模板名称。
3. 视图
greeting.html 在资源文件夹模板目录下:
<!DOCTYPE HTML><html xmlns:th="http://www.thymeleaf.org"><head> <title>Getting Started: Serving Web Content</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /></head><body> <p th:text="'Hello, ' + ${name} + '!'" /></body></html>
这是 thymeleaf 风格的模板。其中 th:text=“表达式” 表示修改 <p> 元素的 text 属性。 ${name} 从模型中获取对象 name。
4. 程序启动代码
@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
非常简单,要点:
- @SpringBootApplication 注释申明了这个类,等价于四个注释。
- main()方法中,SpringApplication.run() 这个配置的程
其实,这个程序有许多默认的配置,如:模板的目录,静态文件的目录。如果要修改这些,可能要读 spring boot 上百页文档。例如,要添加一个过滤器?请阅读:http://docs.spring.io/spring-boot/docs/1.4.2.RELEASE/reference/htmlsingle/#boot-features-embedded-container
这对熟悉 servlet 的程序猿,无疑是痛苦的负担,除非你打算成为 spring boot 的专责程序猿。
5. pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.springframework</groupId> <artifactId>spring-mvc-demo</artifactId> <version>0.1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.1.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <properties> <java.version>1.8</java.version> </properties> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>
它最大好处就是依赖配置简单,几乎 spring 所有模块都下载了。
6. 运行
一般情况下,使用 maven 运行,debug 除外。在 pom.xml 目录输入命令:
mvn spring-boot:run
程序运行,web 服务器启动在 8080 端口。输入:
curl http://localhost:8080/greeting?name=User
三、用传统 XML 配置实现 spring4 mvc
1. 程序结构
这是一个传统的 Spring MVC 程序,也是标准的 web servlet 2.3 + 的程序结构。java 源代码目录 /src/main/java;默认资源目录变为 /src/main/webapp/WEB-INF,其中 web.xml 是 servlet 应用配置,hello-servlet.xml 是 spring beans 的配置。
2. web servlet 应用启动配置
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app> <servlet> <servlet-name>hello</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- spring mvc 静态资源 404问题 : http://blog.csdn.net/this_super/article/details/7884383 --> <servlet-mapping><servlet-name>default</servlet-name><url-pattern>*.html</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list></web-app>
这对新手可能理解困难点。servlet 启动了 DispatcherServlet,它的名字 hello,处理的 url 是 “/” 开头的所有 URL,静态资源使用 default Servlet。
由于没有定义<listener>, DispatcherServlet 默认采用 name-servlet.xml 最为 spring 配置文件,这里是 hello-servlet.xml.
3. spring 配置
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> <mvc:annotation-driven/> <context:component-scan base-package="hello"/><!-- SpringResourceTemplateResolver automatically integrates with Spring's own --><!-- resource resolution infrastructure, which is highly recommended. --><bean id="templateResolver" class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver"> <property name="prefix" value="/WEB-INF/templates/" /> <property name="suffix" value=".html" /> <!-- HTML is the default value, added here for the sake of clarity. --> <property name="templateMode" value="HTML" /> <!-- Template cache is true by default. Set to false if you want --> <!-- templates to be automatically updated when modified. --> <property name="cacheable" value="true" /></bean> <!-- SpringTemplateEngine automatically applies SpringStandardDialect and --><!-- enables Spring's own MessageSource message resolution mechanisms. --><bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine"> <property name="templateResolver" ref="templateResolver" /> <!-- Enabling the SpringEL compiler with Spring 4.2.4 or newer can speed up --> <!-- execution in most scenarios, but might be incompatible with specific --> <!-- cases when expressions in one template are reused across different data --> <!-- ypes, so this flag is "false" by default for safer backwards --> <!-- compatibility. --> <property name="enableSpringELCompiler" value="true" /></bean> <bean id="viewResolver" class="org.thymeleaf.spring4.view.ThymeleafViewResolver"> <property name="templateEngine" ref="templateEngine" /></bean></beans>
这里配置略微复杂,要点:
- <context:annotation-config/> 对应 @configuration
- <mvc:annotation-driven/> 对应 @EnableWebMvc
- <context:component-scan base-package="hello"/> 对应 @ComponentScan
- 后面是 thymeleaf 与 spring4 集成需要的配置。 参见 thymeleaf 官网
这样,Spring Dispatcher 就能使用 @注释,分配/映射 URL 并使用 thymeleaf 引擎渲染页面。
4. 控制器
@Controllerpublic class GreetingController { @RequestMapping("/greeting") public String greeting(@RequestParam(value = "name", required = false, defaultValue = "World") String name, Model model) { model.addAttribute("name", name); return "greeting"; } @RequestMapping("/hello") public void sayHello(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().println("<h1>Hello ,!!!!</h1>"); response.getWriter().println("session=" + request.getSession(true).getId()); } // http://stackoverflow.com/questions/7415084/spring-welcome-file-list-correct-mapping @RequestMapping("/") public String root() { return "redirect:/index.html"; }}
控制器程序几乎没有变化。只是为了支持 welcome 页面,以及使用传统 servlet 方式给出了映射。
- /hello 可以让你自由处理输入输出
- / 可以定位到首页
视图,首页支持文件没有变化,只是改变了位置。
5. pom.xml
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.my_project</groupId> <artifactId>spring-mvc-demo-jetty</artifactId> <version>0.1.0</version> <properties> <project.build.sourceEncoding>utf-8</project.build.sourceEncoding> <jetty.version>9.3.7.v20160115</jetty.version> <springframework.version>4.3.3.RELEASE</springframework.version> <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${springframework.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring4</artifactId> <version>${thymeleaf.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>${jetty.version}</version> </plugin> </plugins> </build></project>这个程序最大的缺点就是你必须知道 Java 包之间的依赖,并明白依赖的包是否在运行时需要或仅编译时需要。这对入门者非常不友好!!!
6.运行
运行命令:
mvn jetty:run
服务器也启动在 http://localhost:8080 端口。
四、无 XML 配置实现 spring4 mvc 使用 jetty
从 spring3 开始,Spring 实现了无 xml 配置,包括对 servlet 3+ 规范对 WebContext (web.xml)可编程支持。对 Spring3+ mvc 的核心接口是 WebApplicationInitializer 。实现该接口,就可以直接启动 web 应用,并进行 WebContext 的配置。一般继承该接口的 AbstractDispatcherServletInitializer 实现类,配置 web context。
1. 程序结构
这个程序非常类似 spring-boot 的结构,仅是多了 config 包下两个 Java 类
2. 配置类(Java-based Configuration Class)
SpringServletInitializer 其实就是 web.xml 的 Java 形式。这里仅是比前面多了常用的 UTF-8 汉字支持的过滤器。
public class SpringServletInitializer extends AbstractDispatcherServletInitializer { public static final String CHARACTER_ENCODING = "UTF-8"; public SpringServletInitializer() { super(); } protected WebApplicationContext createServletApplicationContext() { final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(SpringWebConfig.class); // context.register(PersistenceJPAConfig.class); return context; } protected WebApplicationContext createRootApplicationContext() { return null; } protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected Filter[] getServletFilters() { final CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter(); encodingFilter.setEncoding(CHARACTER_ENCODING); encodingFilter.setForceEncoding(true); return new Filter[] { encodingFilter }; }}
SpringWebConfig 类就是 hello-servlet.xml 配置形式
@Configuration@EnableWebMvc@ComponentScan("hello")public class SpringWebConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware { private ApplicationContext applicationContext; public SpringWebConfig() { super(); } public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } /* ******************************************************************* */ /* GENERAL CONFIGURATION ARTIFACTS */ /* Static Resources, i18n Messages, Formatters (Conversion Service) */ /* ******************************************************************* */ /** * Dispatcher configuration for serving static resources */ @Override public void addResourceHandlers(final ResourceHandlerRegistry registry) { super.addResourceHandlers(registry); registry.addResourceHandler("/images/**").addResourceLocations("classpath:/static/images/"); registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/"); registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/"); registry.addResourceHandler("/**/*.html").addResourceLocations("classpath:/static/"); } /* **************************************************************** */ /* THYMELEAF-SPECIFIC ARTIFACTS */ /* TemplateResolver <- TemplateEngine <- ViewResolver */ /* **************************************************************** */ @Bean public SpringResourceTemplateResolver templateResolver(){ // SpringResourceTemplateResolver automatically integrates with Spring's own // resource resolution infrastructure, which is highly recommended. SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); templateResolver.setApplicationContext(this.applicationContext); //templateResolver.setPrefix("/WEB-INF/templates/"); templateResolver.setPrefix("classpath:/templates/"); templateResolver.setSuffix(".html"); // HTML is the default value, added here for the sake of clarity. templateResolver.setTemplateMode(TemplateMode.HTML); // Template cache is true by default. Set to false if you want // templates to be automatically updated when modified. templateResolver.setCacheable(true); return templateResolver; } @Bean public SpringTemplateEngine templateEngine(){ // SpringTemplateEngine automatically applies SpringStandardDialect and // enables Spring's own MessageSource message resolution mechanisms. SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(templateResolver()); // Enabling the SpringEL compiler with Spring 4.2.4 or newer can // speed up execution in most scenarios, but might be incompatible // with specific cases when expressions in one template are reused // across different data types, so this flag is "false" by default // for safer backwards compatibility. templateEngine.setEnableSpringELCompiler(true); return templateEngine; } @Bean public ThymeleafViewResolver viewResolver(){ ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); viewResolver.setTemplateEngine(templateEngine()); return viewResolver; }}
你可能以注意到其中一些 "classpath:" 。这时找静态文件就在 resource 目录下了。
3. 控制器
@Controllerpublic class GreetingController { @RequestMapping("/greeting") public String greeting(@RequestParam(value = "name", required = false, defaultValue = "World") String name, Model model) { model.addAttribute("name", name); return "greeting"; } @RequestMapping("/hello") public void sayHello(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().println("<h1>Hello ,!!!!</h1>"); response.getWriter().println("session=" + request.getSession(true).getId()); } // http://stackoverflow.com/questions/7415084/spring-welcome-file-list-correct-mapping @RequestMapping("/") public String root() { return "redirect:/index.html"; }}你会发现这个程序与前面的控制器一样哦!
4. 运行
pom.xml 同 jetty 版本(XML 配置),资源文件没有变化。所以,运行程序依然是:
mvn jetty:run
服务器也启动在 http://localhost:8080 端口。
五、结论
本文给出了 Spring 官方 Hello world MVC 在 spring boot,jetty 容器中的实现。其中 jetty 中包含 xml 配置 和 无 xml 配置形式。总的感觉,没有常用案例支持,仅依靠官方文档(几乎都有说明,但难找到解决方案),不同形式的配置迁移是比较难配置和调试的。除了 Spring boot 应用, XML 与 java-based 配置几乎都是对应的。
- XML 配置版本:可以使用 spring 2 - 4 任意版本,部署到任意 servlet 容器中运行,网上中文资料最丰富。缺点,程序变大后配置灾难在所难免;
- 无 XML 配置版本:可以使用 spring 3 - 4 版本,部署到 servlet3+ 容器中运行,网上中文资料质量好坏难辨。非常合适以前的系统升级,也合适新手学习(配置类不同程序都类似,拷贝来就能用)
- Spring boot 应用版本: 只能使用 sping 4 和 spring boot,网上中文资料几乎为零。胜在入门容易,几乎零配置,与 Node.js python 等比也算简单的。
【参考】
[1] Web MVC framework http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html
- spring4 mvc 快速入门 - spring boot or not?
- Spring4-快速入门之Spring Boot
- Spring MVC快速入门-Spring boot
- Spring Boot 快速入门
- Spring Boot 快速入门
- Spring boot快速入门
- Spring Boot 快速入门
- Spring Boot 快速入门
- spring-boot快速入门
- Spring Boot 快速入门
- Spring Boot 快速入门
- Spring Boot 快速入门
- Spring Boot快速入门
- Spring Boot 快速入门
- Spring Boot 快速入门
- Spring Boot 快速入门
- Spring Boot 快速入门
- Spring Boot快速入门
- linux内核调试方法
- [Java]系统环境列表
- easyui datebox只显示年月选择,隐藏日期
- Maven生命周期详解
- java日常笔记2016-12-02
- spring4 mvc 快速入门 - spring boot or not?
- Java内部类相关问题的总结与体会
- Android基础-数据存储
- [openCV学习]openCV函数cvtColor()中转为灰度图的背后数学理论
- [System.Runtime.CompilerServices.AccessedThroughPropertyAttribute("")]
- 递归获取指定文件夹下的所有文件
- JAVA中重写equals()方法的同时要重写hashcode()方法
- OO创建对象
- 指针的个人见解(1)