1.Spring MVC 框架介绍
Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,可以选择是使用内置的 Spring Web 框架还是 Struts 这样的 Web 框架。通过策略接口,Spring 框架是高度可配置的,而且包含多种视图技术,例如 JavaServer Pages(JSP)技术、Velocity、Tiles、iText 和 POI。Spring MVC 框架并不知道使用的视图,所以不会强迫您只使用 JSP 技术。Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
2.Spring MVC 优点
Spring MVC 设计思想非常优秀,功能组件划分很细致,实现了模块化分离,并采用了面向方面的编程aop技术更好的降低的程序的耦合度,也使得程序扩展起来非常方便、灵活。
Spring MVC性能非常优秀,能与Spring框架无缝集成,相比Struts2效率更快,Struts2由于采用了值栈、OGNL表达式、struts2标签库等,会导致应用的性能下降。
Spring MVC的学习难度小于Struts2,Struts2用不上的多余功能太多。
Spring MVC很容易就可以写出性能优秀的程序,Struts2要处处小心才可以写出性能优秀的程序(指MVC部分)
3.Spring MVC 主要功能
4.Spring MVC 技术介绍
实现Spring MVC的方式主要有两种,一种是基于配置的方式来实现,另一种是基于注解的方式实现,本文重点主要讲解基于注解的方式来实现Spring MVC。
4.1 Spring MVC的几大核心组件
DispatcherServlet 前端控制器,将请求分派到具体的控制器Controller中
Controller 具体的控制器,完成对系统流程的控制管理
Handler Mapping 映射器,将请求映射到具体的控制器Controller上,前端DispatcherServlet通过此映射,才能将请求分派到具体的控制器 Controller
ViewResolver 和 View ViewResolver为视图解析器,View为视图解析类,两者需结合使用 ,视图解析器是指为返回的视图指定某种解析方案,而视图解析类则为此种解析方案指定具体实现。
Interceptors 拦截器
LocalResolver 本地化解析器
Validate 验证框架
44.2 基于配置的Spring MVC
首先需要配置DispatcherServlet,配置如下:
- <servlet>
- <servlet-name>testMvc</servlet-name>
- <servlet-class>
- org.springframework.web.servlet.DispatcherServlet
- </servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>
- classpath*:/mvcconf/**/*_mvc.xml
- </param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>testMvc</servlet-name>
- <url-pattern>*.mvc</url-pattern>
- </servlet-mapping>
说明:
<param-name> contextConfigLocation </param-name>
指定Spring MVC配置文件的加载路径,若未指定配置文件加载路径,则默认路径为/WEB-INF/[servlet-name]-servlet.xml,如/WEB-INF/ testMvc -servlet.xml
<load-on-startup>1</load-on-startup>加载方式1为启动服务时加载
包含*.mvc的请求,将会被DispatcherServlet拦截
写一个自己的业务处理Controller类
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.springframework.web.servlet.ModelAndView;
- import org.springframework.web.servlet.mvc.Controller;
- public class TestController implements Controller {
- public ModelAndView handleRequest(HttpServletRequest arg0,
- HttpServletResponse arg1) throws Exception {
- ModelAndView mv=new ModelAndView("testSuc");
- mv.addObject("testList", new ArrayList());
- System.out.println("测试springmvc成功");
- return mv;
- }
- }
说明:
通过直接实现Controller 接口或AbstractController抽象类来定义一个Controller
返回一个ModelAndView对象,testSuc是指返回的视图名称,
testList为返回页面的模型数据,页面取的时候直接取这个健对应的值即可,如${testList},
当调用mv.addObject(attributeValue)方法时,此时没有指定存放对象的键,将会默认为实际存放对象的名字,如:
Wusers对应的键为wusers
List<User>对应的键为userList
Set<People>对应的键为peopleSet
等等……
常用到的一些Controller如下:
用于直接跳转页面的
ParameterizableViewController 参数化的视图控制器,
根据配置中的参数来匹配相应的视图,配置如下:
UrlFilenameViewController 路径文件名视图控制器,根据请求路径来匹配要跳转到的文件名,配置如下:
MultiActionController 处理多个请求的控制器,通过继承MultiActionController来实现。
具体调用的方法通过MethodNameResolver方法名解析器来决定 (InternalPathMethodResolver,ParameterMethodNameResolver,PropertiesMethodResolver)
方法签名: public (ModelAndView | Map | String | void) actionName(HttpServletRequest request, HttpServletResponse response, [,HttpSession] [,AnyObject]);
配置如下:
能封装表单参数的CommandController、FormController
CommandController command对象控制器,通过继承AbstractCommandController来实现,,Spring MVC中将能够接收页面数据的业务模型(JavaBean)称之为command对象,配置如下:
FormController 表单控制器,通过继承SimpleFormController来实现,配置如下:
添加Spring MVC的相关配置如下:
说明:
<prop key="testControl.mvc">testController</prop>表示将请求路径testControl.mvc映射到testController上,其中testController对应bean id
prefix表示为要为视图添加的前缀,suffix表示要为视图的后缀,视图解析器将将对返回的视图路径进行处理,最终返回的路径为:
prefix+视图名称+ suffix,
如当返回的视图名称为testSuc时,最终视图解析器获取到的视图路径为:/WEB-INF/jsp/testSuc.jsp
常用的映射器如下:
SimpleUrlHandlerMapping,基于请求路径的映射器,配置参考上面示例代码
默认的ControllerClassNameHandlerMapping,根据请求路径与控制器的类型进行匹配,默认按控制器的全小写名称进行匹配,可进行设置,如LoginMultiController对应的请求路径应为/loginmulti.mvc,配置如下:
BeanNameUrlHandlerMapping 根据请求路径与bean name进行匹配的映射器,配置如下:
常用到的视图解析器如下:
UrlBasedViewResolver,基于请求路径的视图解析器,配置参考上面示例代码
InternalResourceViewResolver 内部资源视图解析器,可以不用指定viewClass,默认的视图解析类viewClass为JstlView,配置如下:
基于注解的Spring MVC
开发步骤与基于配置的Spring MVC类似,细节上有些出入,具体步骤如下:
配置DispatcherServlet
写一个自己的业务处理Controller类
添加Spring MVC的相关配置
注解请求处理流程
配置DispatcherServlet
写一个自己的业务处理Controller类
添加Spring MVC的相关配置
常用的注解说明以及示例
@Controller注解
作用级别为类级别,用此注解来声明一个控制器Controller
@RequestMapping 注解
作用级别为类级别和方法级别,类级别上此注解可有可无,但是方法级别上,若要求此方法处理请求,则必须使用此注解,当类级别使用了此注解时,如@RequestMapping("/control"),则请求具体的方法如:@RequestMapping("/loginInit") 时必须在方法的请求路径前加上根路径:/control/loginInit
注解参数:
value 设置方法对应的请求路径,当什么参数都不指定,只给一个字符串时,如:@RequestMapping("/testCommand")和@RequestMapping(value="/testCommand")效果一样
method 设置执行方法的请求类型,为枚举类型,可取的值如下:
RequestMethod.GET 表示请求类型为get时执行此方法
RequestMethod.POST 表示请求类型为post时执行此方法
RequestMethod.DELETE 同理
RequestMethod.PUT 同理
等……
headers 设置请求头
params 设置要获取的请求参数名称
@PathVariable注解
作用级别为方法参数级别,restful风格,需要在@RequestMapping的请求路
路径中定义想要的模板参数,如:
@RequestParam注解
作用级别为方法参数级别,从request中获取相应的参数,与
request.getParameter(“xx”)等效,如:
@InitBinder注解
作用级别为方法级别,当command对象封装表单数据时,会调用此绑定初始化方法,可用此方法来对注册自定义的日期属性编辑器,Spring MVC 中绑定属性到相应的command对象时,会去调用与属性类型相匹配的属性编辑器对属性做相应的处理或转换,Spring MVC中对class,url,String,int,float等基础类型都提供了默认的属性编辑器,而没有提供日期类型的属性编辑器,因为日期格式的样式繁多,所以对于日期类型的属性,我们需要自己提供自定义的属性编辑器,或者使用Spring MVC提供的自定义属性编辑器,如下:
@ResponseBody注解
作用级别为方法级别和方法返回参数级别,表示将返回的数据以流的形式进行响应,如:
@Autowired @Qualifier注解
作用级别为成员变量级别,表示自动注入对应的成员变量,单独使用@Autowired注解时将 byType来进行自动注入,此时必须保证成员变量对应匹配的类型至少有一个且只能有一个,当匹配到的类型不止1个时,需要结合@Qualifier(“beanId/beanName”)使用,将会通过byId或者byName的方式来进行匹配并注入,@Qualifier不能单独使用,使用了此注释,无需再为成员变量提供setXX()方法,如:
@Autowired@Qualifier("userInfoService")
private IUserInfoService userInfoService;
@Service注解
作用级别为类级别,用了此注解的类,表示为服务类,将为此类自动生成spring bean的相关配置,不需要再手动配置,如:
此时可将TestMvcBizImpl相关的spring配置去掉,如:
@Service("testBiz"),指定了该类的 bean id为testBiz,若不指定,如直接使用@Service,则会根据类名提供一个默认的bean id,区分大小写,如testMvcBizImpl
Spring MVC的json使用
Spring MVC支持内置的json转换,也可以不用Spring MVC内置的json转换,如使用goole的json转换等。
Spring MVC 自带的json使用
引入依赖的两个json jar包,如下:
request.getParameter(“xx”)等效,如:
方法修改如下:以某些方法为例:
@InitBinder注解
作用级别为方法级别,当command对象封装表单数据时,会调用此绑定初始化方法,可用此方法来对注册自定义的日期属性编辑器,Spring MVC 中绑定属性到相应的command对象时,会去调用与属性类型相匹配的属性编辑器对属性做相应的处理或转换,Spring MVC中对class,url,String,int,float等基础类型都提供了默认的属性编辑器,而没有提供日期类型的属性编辑器,因为日期格式的样式繁多,所以对于日期类型的属性,我们需要自己提供自定义的属性编辑器,或者使用Spring MVC提供的自定义属性编辑器,如下:
@ResponseBody注解
作用级别为方法级别和方法返回参数级别,表示将返回的数据以流的形式进行响应,如:
@Autowired @Qualifier注解
作用级别为成员变量级别,表示自动注入对应的成员变量,单独使用@Autowired注解时将 byType来进行自动注入,此时必须保证成员变量对应匹配的类型至少有一个且只能有一个,当匹配到的类型不止1个时,需要结合@Qualifier(“beanId/beanName”)使用,将会通过byId或者byName的方式来进行匹配并注入,@Qualifier不能单独使用,使用了此注释,无需再为成员变量提供setXX()方法,如:
@Autowired@Qualifier("userInfoService")
private IUserInfoService userInfoService;
@Service注解
作用级别为类级别,用了此注解的类,表示为服务类,将为此类自动生成spring bean的相关配置,不需要再手动配置,如:
此时可将TestMvcBizImpl相关的spring配置去掉,如:
@Service("testBiz"),指定了该类的 bean id为testBiz,若不指定,如直接使用@Service,则会根据类名提供一个默认的bean id,区分大小写,如testMvcBizImpl
Spring MVC的json使用
Spring MVC支持内置的json转换,也可以不用Spring MVC内置的json转换,如使用goole的json转换等。
<bean id="testMvcBiz" class="org.mvc.login.controller.TestMvcBizImpl"></bean>
Spring MVC 自带的json使用
引入依赖的两个json jar包,如下:
- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
- <property name="messageConverters">
- <list>
- <ref bean="jsonConverter" />
- </list>
- </property>
- </bean>
- <bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
- </bean>
添加json 相关的Spring MVC配置,如下:
- @RequestMapping(value="/mvcjsonTest")
- public @ResponseBody Object mvcjsonTest(){
- List list=new ArrayList();
- User user =new User();
- user.setUserId("1100");
- user.setUserName("郑云飞");
- user.setPassword("123456");
- user.setCity("03");
- user.setLoginDate(new Date());
- Map map=new HashMap();
- map.put("testmap1", "map1");
- map.put("testmap2", "map2");
- list.add(map);
- list.add(user);
- return list;
- }
写一个json请求处理方法,如下:
将返回list对应的json格式字符串响应给页面,是通过Spring MVC内置的json处理类将java对象转换成了对应的json格式字符串,并设置contentType=”application/json;charset=UTF-8”,若页面用到了jquery,则jquery会根据返回的contentType自动将json格式的字符串转换为对应的js对象,无需设置jquery的dataType:”json”属性
Spring MVC中使用goole的json
引入goole对应的json jar,如下:
写一个json请求处理方法,如下:
- /**
- * @description: 使用gjson来将java对象转换成json数据格式
- * 无需在springmvc中添加任何相关的json配置,
- * 直接用@ResponseBody注解将转换后的json格式字符串以流的形式响应出去即可,
- * 相当于response.getWriter.out(),
- * 前台得到的响应数据为一个json格式的字符串
- *
- * 当前台使用jquery ajax请求时,若指定了dataType:"json",
- * js会自动将得到的json字符串转换为对应的js对象
- *
- * @return
- */
- @RequestMapping(value="/gjsonTest")
- public @ResponseBody String gjsonTest(){
- User user =new User();
- user.setUserId("1100");
- user.setUserName("郑云飞");
- user.setPassword("123456");
- user.setCity("03");
- user.setLoginDate(new Date());
- JsonObject json=new JsonObject();
- json.addProperty("userInfo", JsonUtil.getJsonStr(user));
- // json.add("userInfo", JsonUtil.getJsonEle(user));
- return json.toString();
- }
拦截器Interceptors
以下代码未经过测试。
定义一个拦截器
通过实现HandlerInterceptor接口来定义一个拦截器,代码如下:
- public class TestInterceptor implements HandlerInterceptor{
- //生成视图之后调用的方法,可用来释放资源等
- public void afterCompletion(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception arg3)
- throws Exception {
- }
- //控制器之行为,生成视图之前调用的方法,如向数据模型中加入公共的成员或日期类型设置等
- public void postHandle(HttpServletRequest request,HttpServletResponse response,
- Object handler, ModelAndView mv) throws Exception {
- }
- //到达拦截器时的预处理方法
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
- Object handler) throws Exception {
- return false;//false表示终止拦截器链,true表示继续执行拦截器链
- }
- }
- <mvc:interceptors>
- <mvc:interceptor>
- <mvc:mapping path="/springmvc/*" />
- <bean class="org.mvc.login.controller.TestInterceptor"></bean>
- </mvc:interceptor>
- </mvc:interceptors>
添加拦截器相关的Spring MVC配置,如下:
国际化使用
- 引入spring标签库
- <%@taglib uri="http://www.springframework.org/tags" prefix="spring" %>
- <spring:message code=”welcome” ></spring:message>
以下代码未经过测试。
在页面中使用spring 标签,如下:
建立对应的资源文件,在src目录下
mess_en_US.properties 美国资源文件 配置为:welcome =welcome
mess_zh_CN.proerties 中国资源文件 配置为:welcome =欢迎
mess.properties 默认资源文件 配置为:welcome =欢迎
添加国际化相关的Spring MVC配置如下:
- <!-- 将会自动加载当前类路径classpath下以mess开头的资源文件-->
- <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
- <!-- mess为资源文件的根路径,去掉语言和国家 -->
- <property name="basename" value="mess"></property>
- </bean>
框架验证 @Valid
以下代码未经过测试。
导入验证所需要的jar包(可自行去网上下载)
hbernate-validator-4.1.0-Betal.jar
validation-api-RO.OGA.jar
slf4j-api-1.5.6.jar
slf4j-log4j12-1.5.6.jar
在代码中使用@Valid来进行验证
- public String saveUser(@Valid User user,BindingResult result){
- public class User {
- @NotEmpty
- private String userId;
- @size(max=32,min=6)
- private String userName;
- public String getUserId() {
- return userId;
- }
- public void setUserId(String userId) {
- this.userId = userId;
- }
- public String getUserName() {
- return userName;
- }
- public void setUserName(String userName) {
- this.userName = userName;
- }
- }
Struts2 迁移Spring MVC总结
- <!--springmvc前端控制器配置 -->
- <servlet>
- <servlet-name>springmvc</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath*:/mvcconf/**/*_mvc.xml</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>springmvc</servlet-name>
- <url-pattern>/springmvc/*</url-pattern>
- </servlet-mapping>
配置DispatcherServlet,如下:
- <context:component-scan base-package="com.cepri.csweb.springmvc.*" />
- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- </bean>
配置视图解析器如下:
BaseAction 迁移
去掉BaseAction继承和实现的接口:
- public class BaseAction extends ActionSupport implements ServletRequestAware, ServletResponseAware {
- ……
- ……
- }
- publicvoid setServletRequest(HttpServletRequest request) {
- this.request = request;
- }
- publicvoid setServletResponse(HttpServletResponse response) {
- this.response = response;
- }
去掉BaseAction中的response属性:
- protected HttpServletResponse response;
对BaseAction中的request属性加入@Autowired注解,实现byType的自动注入:
- @Autowired
- protected HttpServletRequest request;
json处理转移(保留gson来进行json转换)
如,验证码处理类ImageCodeAction修改如下:
在类上加入@Controller注解,如下:
- @Controller
- publicclass ImageCodeAction extends BaseAction {
- ……
- ……
- }
在excute方法上加入@RequestMapping(“/imageCodeAction”)的注解,并加入response参数,如下:
- /**
- * 获取验证码
- */
- @RequestMapping("/imageCodeAction")
- public String execute(HttpServletResponse response){
- ……
去掉属性verifyWord,并去掉对应的set和get方法,如下:
- private String verifyWord;
- public String getVerifyWord() {
- return verifyWord;
- }
- public void setVerifyWord(String verifyWord) {
- this.verifyWord = verifyWord;
- }
在checkVerifyWord方法上加入@RequestMapping(“/imageCodeAction/checkVerifyWord”),返回参数前加上@ResponseBody注解,并加入String verifyWord参数如下:
- /**
- * AIAX方式校验验证码
- */
- @RequestMapping("/imageCodeAction/checkVerifyWord")
- public @ResponseBody String checkVerifyWord(String verifyWord){
- String res = "false";
- HttpSession httpSession = request.getSession();
- String word = (String)httpSession.getAttribute(GlobalConstant.VERIVYWORD);
- if(verifyWord != null && verifyWord.length() != 0){
- if(verifyWord.equals(word)){
- res = "true";
- }
- }
- //JsonUtil.doAjaxReturn(res);
- return res;
- }
Action的转移
包括页面参数传递修改,action返回页面参数修改,json处理修改以及成员变量的注入修改,以WusersAction为例说明
成员变量修改如下:其他成员变量都去掉,并去掉所有成员变量的set,get方法
- /**
- * 密码修改成功消息提示
- */
- public static final String PWD_UPDATE_SUC = "02";
- /**
- * 用户消息
- * */
- @Autowired @Qualifier("iWmsgRcvService")
- private IWmsgRcvService iWmsgRcvService;
- /**
- * 业务操作实体类
- */
- @Autowired @Qualifier("userInfoService")
- private IUserInfoService userInfoService;
- /**
- * 帐户行为日志类
- */
- @Autowired @Qualifier("wActionLog")
- private IWActionLog wActionLog;
方法修改如下:以某些方法为例:
- /**
- * @title :修改用户信息前查询用户信息
- * @author: 郑云飞
- * @date: 2011-9-13
- */
- @RequestMapping("/preUpdWusers")
- public ModelAndView preUpdWusers() {
- ModelAndView mv=new ModelAndView("/jsp/mvc_ms/kongjian_xiugai.jsp");
- try {
- Wusers wusers = userInfoService.findWusers(getUser().getUserId());
- List<Select> areaList = userInfoService.getCityList();
- List<Select> countyList = userInfoService.getCountyList(wusers.getCityNo());
- String mobileSwitch=GlobalUtil.getProperties("turnOnMobile");
- mv.addObject("wusers",wusers);
- mv.addObject("areaList",areaList);
- mv.addObject("countyList",countyList);
- mv.addObject("mobileSwitch",mobileSwitch);
- } catch (Exception e) {
- BaseLog.writeErrorInfo(this.getClass(), "preUpdWusers", e);
- }
- return mv;
- }
- /**
- * 手机绑定
- */
- @RequestMapping("mobileBind")
- public @ResponseBody String mobileBind(Wusers wusers,String mobileCode,String code) {
- try {
- JsonObject jsObj = mobileBindValidate(wusers,mobileCode,code);
- if (jsObj.entrySet().isEmpty()) {
- Wusers wuser = userInfoService.findWusers(getUser().getUserId());
- wuser.setMobile(wusers.getMobile());
- userInfoService.mobileBind(wuser);
- jsObj.addProperty("key", "99");
- }
- return jsObj.toString();
- //JsonUtil.doAjaxReturn(jsObj.toString());
- } catch (Exception e) {
- BaseLog.writeErrorInfo(this.getClass(), "mobileBind 手机绑定", e);
- }
- return "";
- }
页面中需要将原来的struts标签替换为jstl标签,如下
- 原来:
- <s:select id="cityNo" list="areaList" value="wusers.cityNo" cssClass="select" name="wusers.cityNo" listKey="code" listValue="value" onchange="changeCountyList(this.value)"> </s:select>
- 替换为:
- <select id="cityNo" name="cityNo" onchange="changeCountyList(this.value)" class="select">
- <c:forEach items="${areaList}" var="area">
- <option value="${area.code}">${area.value}</option>
- </c:forEach>
- </select>
- 原来jsp中传递的参数:
- <input type="hidden" name="wusers.userId" value="${wusers.userId }" id="userId"/>
- <input type="hidden" name="wusers.loginName" id="loginName" value="${wusers.loginName }"/>
- 需修改如下:直接用对象的属性名,不能再使用原来的 对象.属性名 的形式
- <input type="hidden" name="userId" value="${wusers.userId }" id="userId"/>
- <input type="hidden" name="loginName" id="loginName" value="${wusers.loginName }"/>
- Js中传递参数也需要按上面规则来改