Spring的mvc在2.5的时候尝试过一次,感觉配置繁琐,比struts2还难用
但看了3.0后,感觉新的基于注解的mvc变得简单易用,而且强大。。。。
附上Spring mvc的简易入门教程,我使用的是注解
首先下载需要的jar文件,我用到的有
aopalliance-1.0.jar
c3p0-0.9.1.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-fileupload-1.2.1.jar,commons-io-1.3.2.jar
commons-lang-2.3.jar
commons-logging-1.1.1.jar
jackson-all-1.7.3.jar
jstl.jar
log4j-1.2.16.jar
mysql-connector-java-5.1.10-bin.jar
org.springframework.aop-3.0.4.RELEASE.jar
org.springframework.asm-3.0.4.RELEASE.jar
org.springframework.beans-3.0.4.RELEASE.jar
org.springframework.context-3.0.4.RELEASE.jar
org.springframework.core-3.0.4.RELEASE.jar
org.springframework.expression-3.0.4.RELEASE.jar
org.springframework.jdbc-3.0.4.RELEASE.jar
org.springframework.transaction-3.0.4.RELEASE.jar
org.springframework.web-3.0.4.RELEASE.jar
org.springframework.web.servlet-3.0.4.RELEASE.jar
standard.jar
commons-codec-1.4.jar
其中标注为红色的包,为非必须的,可以根据情况自由选择
下面配置 web.xml文件
添加如下内容
<servlet> <servlet-name>appServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
指定spring mvc配置文件的位置
然后在 WEB-INF目录下建立servlet-context.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 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/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- @Controller, @Service, @Configuration, etc. --> <context:component-scan base-package="com.web" /> <!-- Enables the Spring MVC @Controller programming model --> <mvc:annotation-driven /> <!-- Enable placeholderConfig --> <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>classpath:database.properties</value> </property> </bean> <!-- Configuration dataSource --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${driverClass}" /> <property name="jdbcUrl" value="${url}"/> <property name="user" value="${username}"/> <property name="password" value="${password}"/> <property name="acquireIncrement" value="1"/> <property name="minPoolSize" value="5"/> <property name="maxPoolSize" value="50"/> <property name="maxIdleTime" value="1800"/> <property name="maxStatements" value="0"/> <property name="idleConnectionTestPeriod" value="1800"/> </bean> <!-- Enable transactionManager --> <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="*" propagation="REQUIRED" /> </tx:attributes> </tx:advice> <aop:config> <!-- Configuration Transaction --> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.web.service.*.*(..))" /> </aop:config> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> </bean> <!-- FileUpload Support --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" /> <!-- Support static resource <mvc:resources mapping="/js/**" location="/js/" /> <mvc:resources mapping="/css/**" location="/css/" /> <mvc:resources mapping="/images/**" location="/images/" /> --> <mvc:default-servlet-handler/> <!-- Spring Interceptors --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/admin/*"/> <bean class="com.web.interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors> <!-- Support json ResponseBody --> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="mappingJacksonHttpMessageConverter" /> </list> </property> </bean> <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" /> </beans>
配置文件方面,spring的常见配置就不在累述
其中org.springframework.web.servlet.view.InternalResourceViewResolver 这里配置视图文件位置, 我配置的是/WEB-INF/views 目录下后缀为jsp的文件
下面这个配置是,开启sring的文件上传功能
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
这些则是配置静态资源的路径,比如js,和图片,这样就不用被spring mvc进行解析处理
<!-- Support static resource -->
<mvc:resources mapping="/js/**" location="/js/" />
最下面的注释为<!-- Support json ResponseBody -->的配置是,是配置spring的返回json功能
OK,下面开始写demo代码
控制器的代码如下
package com.web.controller; import java.util.HashMap; import java.util.Map; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; import com.web.service.HelloWorldService; @Controller public class HelloWorld { private HelloWorldService helloWorldService; @Resource(name="helloWorldService") public void setHelloWorldService(HelloWorldService helloWorldService) { this.helloWorldService = helloWorldService; } @RequestMapping(value="/helloworld") @ResponseBody public Map<String,Object> renderJson(@RequestParam(value="id",required=false) Integer id,HttpServletRequest req){ Map<String,Object> map = new HashMap<String, Object>(); map.put("say", helloWorldService.sayHello()); map.put("test", "value"); return map; } @RequestMapping(value="/test") public ModelAndView renderView(){ ModelAndView mv = new ModelAndView(); mv.setViewName("test"); mv.addObject("key", "value"); return mv; } @RequestMapping(value="/upload") public ModelAndView uploadFile(@RequestParam("file") MultipartFile file){ System.out.println(file.getContentType()); System.out.println(file.getOriginalFilename()); System.out.println(file.getSize()); ModelAndView mv = new ModelAndView(); mv.setViewName("view"); mv.addObject("result", "success"); return mv; } }
上面三个方法分别定义了三个url路径,为/helloworld,/test,/upload
其中/helloworld 返回的是一个Map对象,这个map对象在返回给客户端的时候会自动转化为json字符串
/test 返回一个 ModelAndView 对象,这个对象里面包含了要返回的视图名称和一些展示数据,在视图页面可以使用el 和jstl进行取值展示,类似于servlet的forward
/upload 上传文件的处理路径,上传的文件会被spring自动封装为一个MultipartFile对象,可以对此对象进行相关操作。
spring 会自动把传递的参数注入到方法的参数中,这里有个问题,比如public Map<String,Object> renderJson(@RequestParam("name") String name) 这个方法需要一个参数名为name的参数,如果在浏览器访问这个路径的时候没有带上这个name参数,则会获得400的错误。解决办法是使用public Map<String,Object> renderJson(HttpServletRequest req) 这个方法代替,自己从req中取得参数。
好了,控制器的代码完成了。
下面完善service代码
service类为
package com.web.service; public interface HelloWorldService { public String sayHello(); } package com.web.service.impl; import javax.annotation.Resource; import org.springframework.stereotype.Service; import com.web.dao.HelloWorldDao; import com.web.service.HelloWorldService; @Service("helloWorldService") public class HelloWorldServiceImp implements HelloWorldService { private HelloWorldDao helloWorldDao; @Resource(name="helloWorldDao") public void setHelloWorldDao(HelloWorldDao helloWorldDao) { this.helloWorldDao = helloWorldDao; } @Override public String sayHello() { return helloWorldDao.sayHello(); } }
通过 @Service("helloWorldService") 这个注解注册名称为helloWorldService的HelloWorldServiceImp类到spring容器中
@Resource(name="helloWorldDao") 这个注解表示 给这个类中注入 HelloWorldDao的实现类
最后是Dao层的代码
package com.web.dao; public interface HelloWorldDao { public String sayHello(); } package com.web.dao.impl; import org.springframework.stereotype.Repository; import com.util.LogUtil; import com.web.dao.HelloWorldDao; @Repository("helloWorldDao") public class HelloWorldDaoImp extends BaseDaoImp implements HelloWorldDao { @Override public String sayHello() { String testSql = "set names utf8"; String insert = "insert user(name) values(?)"; this.getJdbcTemplate().execute(testSql); this.getSimpleJdbcTemplate().update(insert, "test"); //int i = 1/0; test rollback LogUtil.info(testSql); return "hello"; } }
BaseDaoImp这个类作为所有Dao的基础类,提供操作JdbcTemplate和SimpleJdbcTemplate的访问接口,其中的
package com.web.dao.impl; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; public class BaseDaoImp{ private DataSource dataSource; private JdbcTemplate jdbcTemplate; private SimpleJdbcTemplate simpleJdbcTemplate; public DataSource getDataSource() { return dataSource; } @Autowired public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); this.dataSource = dataSource; } public JdbcTemplate getJdbcTemplate() { return jdbcTemplate; } public SimpleJdbcTemplate getSimpleJdbcTemplate() { return simpleJdbcTemplate; } }
这段代码为自动注入DataSource
其中//int i = 1/0; test rollback 这行代码为测试时候,事物在出现异常后会自动回滚
至此基本告一段落。
可以看到以前的一些大段的配置,已经变为了代码里的注解,这样确实可以快速开发。 但缺点是没有使用xml配置明了。。。
还有一个不知道算不算问题,这样利用注解配置,每个controller里面有可能包含还多url路径方法,以前的action泛滥有可能变成一个类包含太多的逻辑而变的异常庞大
最后还发现一个问题,就是下面这段代码
<mvc:resources mapping="/js/**" location="/js/" />
<mvc:resources mapping="/css/**" location="/css/" />
<mvc:resources mapping="/images/**" location="/images/" />
如果在上面的目录中含有后缀为rar的文件,则访问此文件会出现404的错误,具体原因不知。。。
用<mvc:default-servlet-handler/> 替代上面的静态资源映射,问题解决。
注意:这个一个bug为后来发现,所以附件的项目工程中servlet-context.xml并未更正,请自己更正。
最后附上项目源码,为eclipse3.5jee的web项目