搭建springMVC框架-01
我上学那会流行的是struts,但是等我13年毕业工作的时候springMVC开始变得更加流行了,所以我又学了学springMVC,学的不算深入,但是应付开发没问题了。之前搭建的是spring-3.x的,今天下午又搭建了一次spring-4.x,耽误了很久才彻底弄好,这里还是记一下笔记吧,方便我,也方便大家。我这里只是记录搭建的步骤,不是具体的深入讲解springMVC,所以不适合那些刚刚接触springMVC的读者,不过如果只是看搭建的过程的话,完全没问题。
提前说一下,我这里使用的版本是spring-4.1.6.RELEASE版本。
1、建立工程
先建立一个maven工程,在eclipse中(这里我使用的是spring集成的eclipse,spring tool suite,简称sts,在spring的官网spring,io中可以下载到),new maven project ,选择web骨架,然后在pom中添加如下的dependency,
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.1.6.RELEASE</version> </dependency>
2、编辑web.xml
因为springMVC是一个servlet,所以要在web.xml里面写上springMVC的dispatchServlet,代码如下:
<servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
里面参数的意思是
contextConfigLocation:springMVC的配置文件,这里写的是classpath下的mvc.xml,名字随意,然后把这个文件放在maven项目的resource文件夹下就可以了。mvc.xml的结构如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> </beans>
其中的明明空间先不用管,等到我们使用到特定的标签的时候再加也可以的。
load-on-startup的意思是这个servlet在tomcat启动的时候就创建,而不是等到有访问的时候才会创建,一般的servlet如果不配置load-on-startup则只有在访问的时候才会实例化,而且在整个tomcat的声明周期中只实例化一次。其中参数1表示实例化的先后顺序,越小,越早创建。
然后对应的springMVC的servlet的servlet-mappiing的配置,这里配置的是*.do,表示所有的以.do结尾的请求被这个servet拦截。这里的配置是有讲究的,不要配置为/,这样的话就会覆盖tomcat的默认的servlet,而这个默认的servlet的作用十分强大,我们对js css 图片 html等静态资源的访问全部依靠这个servet,具体一点的,当访问失败,比如404 500错误时,返回的那个页面,就是依靠的这个缺省的servlet。当然我们可以将springMVC的servlet配置为/,但是这样的话对于静态资源的访问我们必须还要配置别的东西,我印象中里是配置<resouce>什么的,如果你非要配置为/,那么可以去查看<resource>,这里我配置为*.do。
3、测试
现在就可以启动tomcat测试了,这里我们先进入到dispatcherServlet的源码中,在他的构造方法处设置断点,然后debug启动tomcat,如果发现在设置的断点处停下,就说明配置的成功,至少是dispatcherServlet启动了,然后跑完程序后发现tomcat启动没有报错,就可以了写Hello World了。
4、继续配置
先修改mvc.xml,我依次讲解每个的意思。
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean>
上面配置的是viewResolver,有很多个viewResolver,因为我们从controller跳出后转向的是jsp,所以使用InternalResourceViewResolver,如果跳出后转向的是velocity,那么就要使用不同的viewResolver,这个等集成velocity的时候再细说。viewResolver的配置
·prefix 要跳转的view的位置,也就是在controller中我们返回的ModelAndView或者是String前面补充的前缀,这里/WEB-INF/jsp表示的是WEB-INF下的jsp文件件下。
·suffix 要跳转的view的后缀,也就是在controller中我们返回的ModelAndView或者是String前面补充的前缀,这里用的是jsp,如果是velocity,则可以配置为.vm。
在上面的配置中,如果我在controller中返回的是string “hello”,且这个controller没有标注@responseBody,那么将跳转到 /WEB-INF/jsp/hello.jsp中。这里的跳转类似于servlet中的forward。
继续配置controller的扫描路径:
<!-- 开启注解 --> <mvc:annotation-driven /> <!-- 配置扫描路径 --> <context:component-scan base-package="com.controller" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>
这个配置很重要,在spring的配置文件中,我们可以定义很多的bean,其中就包括我们自己定义的bean,比如service dao controller,但是spring给我们提供了扫描的机制,也就是不用自己在配置文件中写上bean了,而是提供一个机制让spring去自动得将我们需要的bean放入spring的容器中,spring的解决办法是提供一个路径,然后spring会在这个路径中搜索所有的类,如果满足一定的条件就会实例化这个类,然后放入spring的容器中,这里的条件就是用的注解,即如果这个类上有@controller @service @dao @conmponent之一的话就会实例化放入ioc容器。springMVC这里的配置也是一样的。
<mvc:annotation-driven/> 这个的意思是开启注解的功能,
<context:component-scan ...../>这个的作用是配置扫描的路径,use-default-filters 这个的配置很有来头,默认的配置是true,表示只要这个类上面有@controller @service @dao @component这四个的一个,就会放入springmvc的容器,我们这里配置了false,表示禁用这个默认的值,而是指定扫描的注解为@controller,也可以使用排除 即<context:exlude-filter..../>,但是具体的exclude和include怎么配合使用我没有研究,这里只使用<include >的话,的确是不会扫描@service @dao @component的。我已经做过实验。
完成这个配置,可以做个hello world的测试了,我的测试代码如下:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class Test1 { @RequestMapping("/hello.do") public String hello(){ return "hello"; } }
在 WEB-INF/jsp文件夹下创建 hello.jsp,然后访问 localhost:8080/app/hello.do 其中app表示你的web应用的contextPath,如果出现正常的页面,则表示配置成功。
5、不跳转到页面的配置
有时候,我们在前段html可能仅仅是请求一个true false,或者是一个对象的json字符串,这个时候就不需要再跳转到view了,这里需要在controller中配置@responseBody,表示执行完这个方法后不再跳转到view了。关于这个方法的返回值有很多讲究,比如返回的是个string,或者是返回的是个list又或者是map,或者是个bean,还要涉及到编码格式,返回的http响应头等。
这个就要涉及到MessageConvertor了,我们继续在xml中配置如下:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/plain;charset=UTF-8</value> </list> </property> </bean> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>applicaton/json;charset=UTF-8</value> </list> </property> </bean> </list> </property> </bean>
先注意:一定要把这个配置放在<mvc:annotation-driven/>前面,否则这个配置不起作用。在配置spring的xml时我总结的经验就是一定要将<bean/>的配置放在其他的配置的前面,因为其他的配置会使用到bean的配置。
这个bean RequestMappingHandlerAdaptor里面有个叫做messageConverters的list的属性,表示配置的消息转换器,springMVC自动的就会带有很多个消息转换器,比如这里配置的String的转换器 StringHttpMessageConverter,但是我们做实验的时候发现她对中文的支持不了,中文的全部是乱码,我做的实验室这样的:先注释掉上面配置的<bean RequestMappingHandlerAdaptor/> 然后访问如下的代码
@Controller @RequestMapping("/hello") public class HelloWorldController { @RequestMapping("/world.do") @ResponseBody public String hello(){ System.out.println("fsafas"); return "hello 你好"; } }
请一定要将刚刚配置的bean注释掉,然后访问 这个路径,发现返回的是 hello ??,中文的乱码了,说明他的默认的编码字符集不支持中文,我们到StringHttpMessageConverter的源码中一看,他有个属性:DEFAULT_CHARSET 是 ISO-8859-1的,不用多想,一定时没有指定编码他才是用了这个不支持中文的字符集。再打开我们配置的bean,返现就可以返回正常的中文了。
至于下面的MappingJackson2HttpMessageConverter,这个是处理bean的,像我们定义的person类,ArrayList啊,HashMap啊,这个转化器是转化为json字符串返回给浏览器,我们到这个类的源码中看一下他的javadoc
Implementation of {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverter} that can read and write JSON using <a href="http://jackson.codehaus.org/">Jackson 2.x's</a> {@link ObjectMapper}. <p>This converter can be used to bind to typed beans, or untyped {@link java.util.HashMap HashMap} instances. <p>By default, this converter supports {@code application/json} and {@code application/*+json}. This can be overridden by setting the {@link #setSupportedMediaTypes supportedMediaTypes} property. <p>The default constructor uses the default configuration provided by {@link Jackson2ObjectMapperBuilder}. <p>Compatible with Jackson 2.1 and higher.
大致的翻译是能够转化bean和hashamap,将其转化为json,能够通过覆写supportedMediaTypes属性来改变转化的格式。也就是说我们在配置中写的<property name="supportedMediaTypes".../>默认就是application/json类型的,然后我们再看看他的编码是什么,我们到他的父类中AbstractJackson2HttpMessageConverter,发现有个属性DEFAULT_CHARSET 就是UTF-8的,所以貌似我们这里的配置只要写上<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter实验的java代码如下:
//我们新建立一个person类 public class Person { public Person(){} public Person(String name, int age) { super(); this.name = name; this.age = age; } private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } //controller如下 我们是通过ajax的方式访问的world2.do @Controller @RequestMapping("/hello") public class HelloWorldController { @RequestMapping("world2.do") @ResponseBody public Person person(){ return new Person("张三", 20); } @RequestMapping("/world.do") @ResponseBody public String hello(){ System.out.println("fsafas"); return "hello 你好"; } } 访问的ajax代码如下,我们使用的是jquey访问的请一定要加入jquey的js <script type="text/javascript" src="jquery-1.11.3.js"></script> <script type="text/javascript"> $(function(){ $.ajax({ url:"/yourApp/hello/world2.do", success:function(data){ if(data){ alert(data.name); }else{ alert("失败"); } } }); }); </script>
我们访问这个jsp,然后就会alert出 ”张三“。
然后我们把配置的 <property name="supportedMediaTypes"> 注释掉,发现,结果一样,证明了我们的猜想。。
我们在测试一个map的,修改之前的HelloWorldController ,添加如下的模块
@RequestMapping("map.do") @ResponseBody public Map<String,String> map(){ Map<String,String> m = new HashMap<String, String>(); m.put("name", "李四"); m.put("age", "22"); return m; }
然后仍然使用ajax访问,我的ajax的代码如下:
<script type="text/javascript" src="jquery-1.11.3.js"></script> <script type="text/javascript"> $(function(){ $.ajax({ url:"/yourApp/hello/map.do", success:function(data){ if(data){ alert(data.name); }else{ alert("失败"); } } }); }); </script>
我的实验是可以的。
我记得之前的springMVC3中是可以序列化list的,再次做个实验:继续在上面的HelloWorldController中加入如下代码:
@RequestMapping("list.do") @ResponseBody public List<String> list(){ List<String> l = new ArrayList<String>(); l.add("中国"); l.add("捷克"); l.add("日本"); return l; }
然后修改之前的jsp,如下
<script type="text/javascript" src="jquery-1.11.3.js"></script> <script type="text/javascript"> $(function() { $.ajax({ url : "/velocity/hello/list.do", success : function(data) { if (data) { for(var i=0;i<data.length;i++){ alert(data[i]); } } else { alert("失败"); } } }); }); </script>
运行后访问,可以发现,正常,说明是可以序列化list的。