首页 > 编程语言 > 详细

Spring MVC

时间:2016-07-13 14:03:57      阅读:342      评论:0      收藏:0      [点我收藏+]

    Spring为展现层提供了一个优秀的Web框架--SpringMVC。和众多Web框架一样,它基于MVC设计理念,此外,它采用了松散耦合可插拔组件结构,比其他MVC框架更具扩展性和灵活性。

1、SpringMVC概述

    SpringMVC框架是围绕DispatcherServlet这个核心展开的,DispatcherServlet是Spring MVC的总策划,它负责接货请求并将其分派给相应的处理器处理。SpringMVC框架包括注解驱动控制器、请求及响应的信息处理、视图解析、本地化解析、上传文件解析、异常处理以及表单标签绑定等内容。

    1.1、体系结构

        从接收请求到返回响应,Spring框架的众多组件通力合作、各司其职,有条不紊地完成分内工作。在整个框架中,DispatcherServlet处于核心位置,它负责协调和组织不同组件以完成请求处理并返回响应的工作。和大多数WebMVC框架一样,SpringMVC通过一个前端Servlet接收所有请求,并将具体工作委托给其他组件进行处理,DispatcherServlet就是SpringMVC的前端Servlet。SpringMVC处理请求的整体过程如下。

  1. 整个过程始于客户端发出一个HTTP请求,Web应用服务器接收到这个请求,如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),Web容器就将该请求转交给DispatcherServlet处理。

  2. DispatcherServlet接收到这个请求后,将根据请求的信息(包括URL、HTTP方法、请求报文头、请求参数、Cookie等)以及HandlerMapping的配置找到处理请求的处理器Handler。

  3. 当DispatcherServlet根据HandlerMapping得到对应当前请求的Handler后,通过HandlerAdapter对Handler进行封装,再以统一的适配器接口调用Handler。HandlerAdapter是SpringMVC的框架级接口,它用统一的接口对各种handler方法进行调用。

  4. 处理器完成业务逻辑处理的处理后将返回一个ModelAndView给DispatcherServlet,ModelAndView包含了视图逻辑名和模型数据信息。

  5. ModelAndView中包含的是“逻辑视图名”而非真正的视图对象,DispatcherServlet借由ViewResolver完成逻辑视图名到真正视图对象的解析工作。

  6. 当得到真正视图对象View后,DispatcherServlet就使用这个View对象对ModelAndView中的模型数据进行视图渲染

  7. 最终客户端得到响应消息可能是一个普通的HTML页面,也可能是一个XML或JSON串等不同的媒体形式。

    1.2、配置DispatcherServlet

        和任何Servlet一样,用户必须在web.xml文件中配置好DispatcherServlet。要了解Spring MVC框架的工作原理,必须回答一下三个问题

  • DispatcherServlet框架如何截获特定的HTTP请求,交由SpringMVC框架处理的?

  • 位于Web层的Spring容器(WebApplicationContext)如何与位于业务层的Spring容器(ApplicationContext)建立关联,以使Web层的Bean可以调用业务层的Bean

  • 如何初始化SpringMVC的各个组件,并将它们装配到DispatcherServlet中?

    1.2.1、配置DispatcherServlet,截获特定的URL

        我们可以在web.xml中配置一个Servlet,并通过<servlet-mapping>指定其处理的URL。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
 xmlns="http://java.sun.com/xml/ns/javaee" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name></display-name> 
  <!-- 使用Spring提供的日志配置方法 -->
  <context-param>
   <param-name>log4jConfigLocation</param-name>
   <param-value>/WEB-INF/classes/log4j.properties</param-value>
  </context-param>
  <context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
   <context-param>
   <param-name>log4jRefreshInterval</param-name>
   <param-value>3000</param-value>
  </context-param>
   <context-param>
   <param-name>webAppRootKey</param-name>
   <param-value>onlineEdu.root</param-value>
  </context-param>
  <listener>
   <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
  </listener>
  <listener>
   <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <servlet>
   <servlet-name>springDispatcher</servlet-name>
   <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
   <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
   <servlet-name>springDispatcher</servlet-name>
   <url-pattern>*.do</url-pattern>
  </servlet-mapping>
  
  <filter>
   <filter-name>encodingFilter</filter-name>
   <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
   <init-param>
    <param-name>encoding</param-name>
    <param-value>UTF-8</param-value>
   </init-param>
   <init-param>
    <param-name>forceEncoding</param-name>
    <param-value>true</param-value>
   </init-param>
  </filter>
  <filter-mapping>
   <filter-name>encodingFilter</filter-name>
   <url-pattern>/*</url-pattern>
  </filter-mapping>
  <welcome-file-list>
    <welcome-file>login.jsp</welcome-file>
  </welcome-file-list>
</web-app>

    通过contextConfigLocation参数指定业务层Spring容器的配置文件(多个文件用逗号隔开),ContextLoaderListener是一个ServletContextListener,它通过contextConfigLocation参数所指定的Spring配置文件启动“业务层”的Spring容器

    一个web.xml可以配置多个DispatcherServlet

2、注解驱动的控制器

    2.1、使用@RequestMapping映射请求

        在POJO类定义处标注@Controller,再通过<context:componect-scan/>扫描相对应的类包,即可使POJO成为一个能处理HTTP请求的控制器。可以创建数量不限的控制器,分别处理不同的业务请求。每个控制器可以有多个处理请求的方法,每个方法负责不同的请求操作。如何将请求映射到对应的控制器方法中是Spring MvC框架最重要的任务之一,这项任务由@RequestMapping承担。

        在控制器的类定义及方法定义处都可标注@RequestMapping,类定义出的@RequestMapping提供初步的请求映射信息,方法处的@RequestMapping提供进一步的细分映射信息。

        @RequestMapping除了可以使用URL映射请求外,还可以使用请求方法、请求头参数以及请求参数映射请求。@RequestParam("userid") -- 获取请求参数userid的值

package com.zzia.controller.admin;
...//省略import
@Controller
@RequestMapping(value="/admin")
public class AdminController implements Serializable {
 
 private static final long serialVersionUID = 1L;
 private static Logger logger=Logger.getLogger(AdminController.class);
 @Autowired
 private IAdminService adminService;

 @Autowired
 private ILoginLogService loginLogService;
 
 //管理员登陆方法
 @RequestMapping("/login")
 public String login(Admin admin,HttpServletRequest request,HttpSession session){
  logger.warn(admin.getAdminName()+"试图登陆");
  ...
 }
 //更新管理员信息方法
 @RequestMapping("/updateAdmin")
 public String updateAdminInfo(Admin admin,@RequestParam("img") CommonsMultipartFile file,HttpServletRequest request){
  logger.info("更新"+admin.getAdminName()+"的信息");
  ...
 }
 //得到管理员的更新信息
 @RequestMapping("/getAdminInfo")
 public String getAdminInfo(int adminId,HttpServletRequest request){
  logger.info("根据Id得到管理员详细信息"+adminId);
  ...
 }
 //退出登录的方法
 @RequestMapping("/loginOut")
 public String loginOut(HttpSession session){
  logger.info(((Admin)session.getAttribute("adminInfo")).getAdminName()+"退出登录");
  ...
 }
}

    2.2、处理模型数据

        对于MVC框架来说,模型数据是最重要的。Spring提供了以下几个途径将模型数据输出给视图。

  • ModelAndView:处理方法返回值类型为ModelAndView时,方法体即可通过该对象添加模型数据。

  • @ModelAttrbute:方法入参标注该注解后,入参的对象就会放到数据模型中

  • Map及Model:入参为Model和ModelMap或者Map时,处理方法返回时,Map中的数据会自动添加到模型中

  • @SessionAttributes:将模型中的某个属性暂存到HttpSession中,以便多个请求之间可以共享这个属性

    2.3、数据校验

        应用程序在执行业务逻辑前,必须通过数据校验保证接收到的输入数据是正确合法的。为了避免数据的冗余校验,将验证逻辑和相应的域模型进行绑定,将代码验证的逻辑集中起来管理。

        2.3.1、Spring校验框架

            Spring3.0拥有自己独立的数据校验框架,同事支持JSR 303标准的校验框架。Spring的DataBinder在进行数据绑定时,可同时调用校验框架完成数据校验工作。在SpringMVC中,可直接通过注解驱动的方式进行数据校验。

            Spring的org.springframework.validation是校验框架所在的包,Validator接口拥有以下两个方法:

  • boolean supports(Class<?> clazz):该校验器能够对clazz类型的对象进行校验

  • void validate(Object target,Errors erros):对目标类target进行校验,并将校验错误记录在errors中

            LocalValidatorFactoryBean既实现了Spring的Validator接口,也实现了JSR 303的Validator接口路,只要再Spring容器中定义一个LocalValidatorFactoryBean,即可将其注入需要数据校验的Bean中。定义一个LocalValidatorFactoryBean非常简单

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

        注意:Spring本身没有提供JSR 303的实现,所以必须将JSR 303的实现者(如Hibernate Validator)的jar文件放到类路径下,Spring将自动加载并装配好JSR 303的实现者。<mvc:annotaion-driver/>会默认装配好一个LocalValidatorFactoryBean,通过在处理方法的入参上标注@Valid注解即可让SpringMVC在完成数据绑定后执行数据校验工作。

        2.3.2、如何获得校验结果

            只要再表单/命令对象类中标注校验注解,在处理方法对应的入参前添加@Valid,springMVC就会实施校验并将校验结果保存在被校验入参对象之后的BindingResult或Error入参中。在处理方法内部可以通过BindingResult或Errors入参对象获取错误信息。例如通过BindingResult对象的hashErrors()方法判断入参对象是否存在校验错误。

package org.worm.biz.springmvc.controller.hibernate;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.worm.biz.springmvc.dao.User;
import org.worm.biz.springmvc.service.hibernate.IUserService;
/** 
* @ClassName: UserController 
* @Description: TODO 用户操作控制器
* @author Administrator
* @date 2016年7月13日 上午10:12:44 
*  
*/ 
@Controller
@RequestMapping(value="/user")
public class UserController {
 @Autowired
 private IUserService userService;
 
 @RequestMapping("/valid")
 public String handleValid(@Valid @ModelAttribute("user") User user,BindingResult bindResult){
  if(bindResult.hasErrors()){
   return "/user/register";
  }else{
   userService.addEntity(user);
   return "/user/showUser";
  }
 }
 
}

//对User进行校验
package org.worm.biz.springmvc.dao;
import javax.persistence.*;
import javax.validation.constraints.Pattern;

@Entity
//@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Table(name = "t_user")
public class User{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_no")
    @Pattern(regexp = "w{4,30}")
    //通过正则表达式进行校验,匹配4~30个数字和字母以及下划线
    protected int userId;
    @Column(name = "user_nick_name")
    protected String userName;
    protected String password;
    
    @Column(name = "user_age")
    protected String userAge;
    
    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
 public String getUserAge() {
  return userAge;
 }
 public void setUserAge(String userAge) {
  this.userAge = userAge;
 }
    
}

3、视图和视图解析器

    在请求处理方法执行完成后,最终返回一个ModelAndView对象,对应那些返回String、View或者ModelMap等类型的处理方法,Spring MVC内部也会在将它们装配成一个ModelAndView对象,它包含了视图逻辑名和模型对象的信息。Spring MVC借助视图解析器(ViewResolver)得到最终的视图对象(View),这可能是常见的JSP视图,也可能是一个基于FreeMarker、Velocity模板技术的视图,还可能是PDF、Excel、XML、JSON等各种形式的视图。

    3.1、认识视图

        视图的作用:渲染视图模型数据,将模型里的数据以某种形式呈现给客户。Spring提供了一个高度抽象的View接口。该接口中定义了两个方法

  • String getContentType():视图对应的MIME类型,如text/html、imge/jpeg等

  • void render(Map model,HttpServletRequest request,HttpServletResponse response):将模型数据以某种MIME类型渲染出来

    视图类型

技术分享

    3.2、认识视图解析器

        SpringMVC为逻辑视图名的解析提供了不同的策略,可以在Spring Web上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。视图解析器的工作比较单一:将逻辑视图名解析为一个具体的视图对象。解析器都实现了ViewResolver接口,该接口仅有一个方法View resolverViewName(String viewName,Locale locale);

    3.3、JSP和JSTL

        JSP是最常见的视图技术,InternalResourceViewResolver默认使用InternalResourceView作为视图实现类。如果JSP文件使用了JSTL的国际化功能,也即JSP页面使用了JSTL的<fmt:message>等标签是,用户需要使用JstlView替换默认的视图实现类。

        使用Spring MVC表单标签,可以很容易地将模型数据中的表单/命令对象绑定到HTML表单元素中。和使用任何JSP扩展标签一样,在使用Spring表单标签之前,必须先在JSP页面中添加引用

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<html>
    <!-- ...-->
    <!-- 使用<form:form/>标签实例,无须通过action属性指定表单提交的目标url -->
    <form:form modelAttributes="user">
        user:<form:input path="userName"/><br/>
        password:<form:password path="password"/><br/>
        <input type="submit" value="登陆" name="testSubmit"/>
        <input type="rest" value="重置"/>
    </form:form>
</html>

    3.4、模板视图

        FreeMarker和Velocity是除JSP外使用最多的页面模板技术。页面模板编写好页面结构,并使用一些特殊的变量标识符绑定Java对象的动态数据。Spring对FreeMarker和Velocity都提供了支持。由于我对它没什么兴趣,有兴趣的童鞋可自行学习。

    3.5、文件上传

        SpringMVC为文件上传提供了直接的支持,这种支持是通过即插即用的MultipartResolver实现的。Spring使用Jakarta Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver

        3.5.1、配置MultipartResolver

 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="utf-8" />
    <!-- 设置文件上传的最大尺寸 -->
       <property name="maxUploadSize" value="10485760000" />
       <property name="maxInMemorySize" value="40960" />
       <property name="uploadTempDir" value="upload/temp"/> <!-- 上传文件的临时路径-->
 </bean>

    3.5.2、编写控制器和文件上传表单页面

package com.zzia.controller.admin;
...
@Controller
@RequestMapping(value="/admin")
public class AdminController {
 
 private static Logger logger=Logger.getLogger(AdminController.class);
 @Autowired
 private IAdminService adminService;
 
 @Autowired
 private ILoginLogService loginLogService;
 
 //更新管理员信息方法
 @RequestMapping("/updateAdmin")
 public String updateAdminInfo(Admin admin,@RequestParam("img") CommonsMultipartFile file,HttpServletRequest request){
  logger.info("更新"+admin.getAdminName()+"的信息");
  String updateResult="更新失败";
  if(!file.isEmpty()){
   String type=file.getOriginalFilename().substring(file.getOriginalFilename().indexOf("."));//读取文件后缀
   String fileName=System.currentTimeMillis()+type;//取当前时间戳为文件名
   String path=request.getSession().getServletContext().getRealPath("/")+"upload/admin/"+fileName;
   //System.out.println(path);
   File destFile = new File(path);
   try {
    FileUtils.copyInputStreamToFile(file.getInputStream(), destFile);//复制临时文件到指定目录下
   } catch (IOException e) {
    logger.debug("文件上传异常");
   }
   admin.setAdminHead("upload/admin/"+fileName);
  }
  if(adminService.updateAdminInfo(admin)>0){
   updateResult="更新成功";
   logger.info("更新成功");
  }
  request.setAttribute("updateResult", updateResult);
  return "/admin/getAdminInfo.do?adminId="+admin.getAdminId();
 }
}

    SpringMVC会将上传文件绑定到MultipartFile对象中,MultipartFile提供了获取上传文件内容、文件名等内容,通过其transferTo()方法还可将文件存储到硬盘中,具体说明如下:

  • byte[] getBytes():获取文件数据

  • String getContentType():获取文件MIME类型,如image/pjpeg,text/plain等

  • InputStream getInputStream():获取文件流

  • String getName():获取表单中文件组件的名称

  • String getOriginalFileName():获取上传文件的原名

  • long getSize():获取文件的字节大小,单位为byte

  • boolean isEmpty():是否有文件上传

  • void transferTo(File dest):可以使用该文件将上传文件保存到一个目标文件中

    负责上传文件的表单页面和一般表单有一些区别,表单的编码类型必须是”multipart/form-data“

 <form action="admin/updateAdmin.do" method="post" enctype="multipart/form-data">
    <ul class="forminfo">
     <li><label>管理员编号</label><input name="adminId" type="text" readonly="readonly" class="dfinput" value="${admin.adminId}" /></li>
     <li><label>管理员名称</label><input name="adminName" type="text" class="dfinput" value="${admin.adminName }" /></li>
     <li><label>管理员旧密码</label><input  type="password" class="dfinput" value="${admin.adminPassword }"/></li>
     <li><label>管理员新密码</label><input name="adminPassword" type="password" class="dfinput" /></li>
     <li><label>更新头像</label><input type="file" name="img"/>
     <a href="javascript:void(0);" onclick="yulan(‘${admin.adminId}‘)" class="infolist" style="display: block;float: left;position: relative;left:200px;">预览</a>
     </li>
    </ul>
    <div id="adminHead">
     <img alt="管理员头像" src="${admin.adminHead }" style="text-align: center;vertical-align: middle;">
    </div>
    <input style="margin-left: 150px;" type="submit" class="btn" value="确认保存"/>
    </form>





本文出自 “阿酷博客源” 博客,请务必保留此出处http://aku28907.blog.51cto.com/5668513/1826012

Spring MVC

原文:http://aku28907.blog.51cto.com/5668513/1826012

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!