前言
作为一个服务端开发感觉一直挺排斥框架这种东西的, 总觉得什么实现逻辑都帮你封装在里面了, 你只需要配置这配置那个, 出了问题也不知道怎么排查, 之前即使写 web 程序也宁愿使用 jetty 这样的嵌入式的 web server 实现, 自己写 servlet, 总感觉从 main 函数开始都在自己的掌控范围之内, 但是这样的方式的确有点原始, 也看到各种各样的开源系统使用 spring 实现 web 服务, 虽然代码总是能够看明白, 但是还是不晓得一步步是怎么搭建的, 于是抽出一个周末折腾折腾, 不搞不知道, 原来这玩意能把一个不熟悉的用户搞崩溃, 本文主要介绍我是如何搭建一个 spring 环境的(话说还真的分不清 spring 和 springmvn), 虽然在大多数 web 开发看来这是雕虫小技.
本文使用的环境是 eclipse luna+spring 比较新的一个版本(按照我选择版本的规则是除非有什么新功能新版本才用, 否则尽量不使用最新的版本, 然后选择较新的 N 个版本中使用人数比较多的, 例如本文选用的 spring 版本是 4.3.7.RELEASE).
下面就从纯工程的角度上解释如何一步步的搭建这样的环境的, 没有原理, 有原理也是我纯属猜测的, 没有看过源码.
详细步骤
第一步: 创建一个 maven 工程
这是再熟悉不过的流程了, 但是一般我不推荐选择 Archetype, 只是创建一个 simple project 就可以了, 前者总是创建失败(创建 Archetype 模式的可以让 IDE 做更多的事情). 其实在何谓 maven 工程, 在我看来就是一个带有 pom.xml 的 java 工程罢了, 然后再把代码的路径设置为 src/main/java 类似这样的结构, 所以我们只需要用 IDE 帮我们创建一个带有 pom.xml 的工程就可以了, 我们自己写一个 dependency 和 build 参数.
配置的时候除了填写正确的 group id 和 artifact id, 主要把 packaging 选择为 war, 这样可以在 tomcat 下运行.
第二步: 修改工程配置
这里需要修改的配置有两个, 只需要注意修改之后的样子就可以了:
1,Project Facets: 虽然不知道这里配置什么的, 但是一次次的吃了这个的亏, 这里要配置的是 Java 选择 1.6 以上(最好 1.7 吧), 然后选择 Dynamic Web Module, 下方出现如下的界面:
这里写图片描述
如果没出现则可以先勾掉 Dynamic Web Module, 然后保存, 然后再次点进去 Project Facets, 选择 Dynamic Web Module, 这时候就出现了这样的界面, 注意最好不要选择 3.0, 之前遇到过 3.0 不兼容的问题, jdk1.7 + 2.5 版本是可以正常运行的.
点进去 "Further configuration avaliable..." 进行配置, 将 Context directory 修改成, 并选择生成 web.xml, 保存. 如下图:
这里写图片描述
此时你会看到你的工程结构如下图, src/main 目录下出现了 java/resources/webapp 三个目录.
这里写图片描述
2, 配置 Deployment Assembly, 这里配置的 Source 和 Deploy Path, 表示在工程部署的时候会将 source 目录下的内容拷贝到 tomcat 部署目录 / Deploy Path 下. 这里需要配置的如下图所示:
这里写图片描述
例如第一条表示会将工程中 src/main/java 目录下的源代码编译之后放到部署目录 / WEB-INF/classes 目录下, 最后一条表示会将该工程的 maven 依赖拷贝到部署目录 / WEB-INF/lib 目录下. 据我观察发现, 其实 tomcat 目录运行过程中会将部署部署目录 / WEB-INF/classes, 部署目录 / WEB-INF/lib 加入到 classpath 中, 所以将配置文件和编译完成的 class 文件放到 classes 下, 依赖的 jar 放到 lib 目录下都是可以在启动 java 程序时找得到的.
第三步: 下载 spring 依赖
spring 的 jar 比较多, 最基本的功能也需要如下的几个 dependency:
- <properties>
- <spring.version>4.3.7.RELEASE </spring.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId> org.springframework</groupId>
- <artifactId> spring-context</artifactId>
- <version> ${spring.version}</version>
- </dependency>
- <dependency>
- <groupId> org.springframework</groupId>
- <artifactId> spring-core</artifactId>
- <version> ${spring.version}</version>
- </dependency>
- <dependency>
- <groupId> org.springframework</groupId>
- <artifactId> spring-beans</artifactId>
- <version> ${spring.version}</version>
- </dependency>
- <dependency>
- <groupId> org.springframework</groupId>
- <artifactId> spring-web</artifactId>
- <version> ${spring.version}</version>
- </dependency>
- <dependency>
- <groupId> org.springframework</groupId>
- <artifactId> spring-webmvc </artifactId>
- <version> ${spring.version}</version>
- </dependency>
- </dependencies>
spring 的不同的依赖使用的版本要保持一致.
第四步: 编写代码
我们写一个简单的 controller, 这个 controller 返回一个 "Hello ${username}" 字符串.
- package com.fengyu.test;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.RequestParam;
- import org.springframework.web.bind.annotation.ResponseBody;
- import org.springframework.web.bind.annotation.RestController;
- @RestController
- @RequestMapping("/test" )
- public class SimpleController {
- @RequestMapping(value = "hello", method = RequestMethod.GET)br/>@ResponseBody
- public String helloWorld(@RequestParam ("user") String userName) {
- return "Hello" + userName + "!" ;
- }
- } mailto:br/%3E@ResponseBody%3Cbr/
- mailto:br/%3E@ResponseBody%3Cbr/
第五步: spring 配置文件
spring 配置文件一般取名叫 "applicationContext.xml", 当然这个不是 spring 默认的配置名, 还是需要在 web.xml 中指定, 这里我们只配置 spring 的配置文件, 其实 spring 配置中主要是对一些 bean 的配置, 这里我们暂时不需要创建任何 bean, 就只需要简单地加一下扫描路径就可以了.
- mailto:br/%3E@ResponseBody%3Cbr/
- <beans xmlns= "mailto:br/>@ResponseBody
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:mvc="http://www.springframework.org/schema/mvc"
- xsi:schemaLocation=" http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
- http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd ">
- <context:annotation-config />
- <!-- 自动扫描 web 包 , 将带有注解的类 纳入 spring 容器管理 -->
- <context:component-scan base-package="com.fengyu.test"></context:component-scan>
- </beans>
这种配置文件一般放在 src/main/resources 目录下, 前面我们已经配置部署拷贝的设置, 他会在部署时被拷贝到 WEB-INF/classes / 目录下, 这里只配置了两项其中 context:annotation-config 是告诉 spring 识别注解配置, 后面的 scan 表示要扫描的类的 package.
第六步: 配置 web.xml
web.xml 使我们第二步配置时自动生成的, 它是 tomcat 启动时需要依赖的配置, 里面可以配置一些 servlet,filter,listener 等, 对于简单使用 spring 而言, 一般只配置一个 servlet, 所有的请求都有这个 servlet 进行路由处理.
- <?xml version= "1.0" encoding ="UTF-8"?>
- <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id= "WebApp_ID" version ="2.5">
- <servlet>
- <servlet-name> DispatcherServlet</servlet-name>
- <servlet-class> org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name> contextConfigLocation</param-name>
- <param-value> classpath:applicationContext.xml</param-value>
- </init-param>
- <load-on-startup> 1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name> DispatcherServlet</servlet-name>
- <url-pattern> /</url-pattern>
- </servlet-mapping>
- </web-app>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
可以看到我们只配置了一个 DispatcherServlet, 它处理所有的 url 请求, 它初始化需要的配置文件会 classpath 下找 applicationContext.xml, 刚才已经介绍, 在部署的时候 resources 下的文件会拷贝到 WEB-INF/classes 目录下并且加入到 java 启动的 classpath 下.
第七步: 部署 tomcat
首先需要下载一个 tomcat,tomcat 7.x 是一个不错的选择, 由于 tomcat 是绿色的(大多数 java 实现的都是绿色的), 可以直接解压, 然后在 eclipse 中配置. 在 eclipse 中 Window->Server->Runtime Environment 中 Add 一个 tomcat 实例, 注意需要选择 jdk, 需要选择当前 jdk 支持的版本.
然后再下方任务栏里面找到 Servers, 如果没有可以再 Window->Show View 中选择 Servers 添加, 添加了之后可以在这里 create a new server. 选择刚刚创建的 tomcat 实例, 然后从 Avaliable 的 resources 中选择一个加入到右边 Configured 中(Avaliable 是根据工程中是否有 web.xml 生成的).
第八步: 配置 tomcat
双击新创建的 Tomcat Server, 进入 Overview 页面, 这个页面可以配置这个工程运行 tomcat 实例, 主要配置包括端口号, 部署目录等等, 如果端口或文件不冲突的话尽量不要修改, 需要修改的一处是 Server Options 中勾选上 "Publish module contexts to separate XML files", 虽然不知道这个是做什么的, 但是血和泪的教训告诉我要选上这个, 直接保存.
第九步: 启动 tomcat
这里可能有人要问了, 为什么 eclipse 上没有配置 tomcat 的插件啊, 我到哪里去启动 tomcat! 难道没有那个猫头就不行了吗? 说实话, 配置那个猫头经常遇到网络问题失败, 于是不再尝试了, 而直接通过右击第七步创建的 tomcat 实例就可以完成猫头所能完成的所有功能, 为什么还配置那个插件呢? 右键 Start, 然后祈祷启动的时候不要出现什么错误, 出现错误就 google 一下吧, 基本上 spring 的问题都有人踩过坑的.
第十步: 测试
启动完成之后, 一般不会出现什么错误, 打开浏览器输入 http://localhost:8080/SpringTest/test/hello?user=World, 此时就可以看到如下的输出:
这里写图片描述
出现了我们想要的结果, 此时的心情只能用愉悦来形容, 但是我们指定了需要携带 user 参数, 如果 url 中不带参数则出现如下的错误:
这里写图片描述
如果不希望出现这样的情况可以再 helloWorld 这个参数的 @RequestParam 修改为 @RequestParam(value="user",required=false, defaultValue="World"), 当然这只是一个非常小的 example 说明注解的强大, spring 还提供了丰富的注解来实现不同的需求, 简直就是用配置和注解来编程.
第十一步: 复杂数据结构
上面的测试都是返回一个 String, 但是我们一般开发的时候会涉及到复杂的数据结构, 大家一般都会用 json 来作为通信的序列化工具, 那么怎么在 spring 中支持 json 呢? 在测试这个之前, 先看一下现在对于复杂数据结构 (例如 Map) 怎么返回的.
我们在 Controller 中添加一个函数:
- @RequestMapping(value = "helloMap" , method = RequestMethod.GET)
- @ResponseBody
- public Map<String, String> helloMap(@RequestParam(value="user" ,required=false, defaultValue= "World") String userName) {
- Map<String, String> ret = new HashMap<String, String>();
- ret.put( "hello", userName );
- return ret ;
- }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
然后再浏览器中测试一下, 出现如下的错误 "The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request"accept"headers.", 这个感觉是因为 accept 默认只接受 text 格式, 而这个接口的返回值没有返回 text 对象.
如果要支持 json, 其实只需要在 spring 中配置一下 message-converters 就可以了, 每一个 json 库都提供这样的 Converter 的, 我们这里以 Fastjson 作为示例吧, 首先需要在 pom.xml 添加 fastjson 的依赖. 然后在 applicationContext.xml 中添加如下配置:
- <mvc:annotation-driven>
- <mvc:message-converters register-defaults="false">
- <bean
- class= "com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
- <property name= "supportedMediaTypes">
- <list>
- <value> text/html; charset=UTF-8</value>
- <value> application/json; charset=UTF-8</value>
- </list>
- </property>
- </bean>
- </mvc:message-converters>
- </mvc:annotation-driven>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
这时候再重试刚才的 url 发现可以返回 map 转换成 json 的样子了.
这里写图片描述
第十一步: 折腾
好了, 上面的示例已经足够完成一个比较简单的 web 服务了, 当然我们还没有前端, 只不过是通常作为服务端提供的 Http 服务罢了, 不过有了 spring 我们可以省去大量的代码, 当然通过 HTTP+JSON 提供服务端接口比 thrift 等 RPC 框架要中一些, 效率或许要低一些, 但是它的优势是比较简单啊, 调试比较方便啊... 感觉大量的前端和服务端通信大都使用这样的方式.
总结
学会了 spring 框架的搭建, 妈妈再也不用担心我写 web 接口了, 当然 spring 还能够适配各种各样的组件, 例如通常使用的 mybatis 连接数据库, jedis 连接 redis 等; 还有丰富的功能让你尽量通过配置和注解降低不必要的代码. 最近比较好的 Spring boot 貌似也是 web 开发神器. 这个以后有时间再折腾.
当然本文只是记录了血泪历程, spring 小白是如何一步步的搭建 spring 开发环境的, 大神轻喷..
来源: http://www.bubuko.com/infodetail-2712069.html