转载

Spring MVC 实践 – Base

Spring Web MVC

Spring-Web-MVC是一种 基于请求驱动的 轻量级Web-MVC 设计模式 框架, Spring MVC使用MVC架构思想, 对Web层进行 职责解耦 ,使用 请求-响应 模型将 数据业务视图 进行分离, 简化开发.

MVC(模型-视图-控制器)是一个 以设计界面应用程序为基础 的架构模式,通过分离模型-视图-控制器在应用中的角色将业务逻辑从界面中解耦:

  • 模型负责封装应用数据和业务逻辑;
  • 视图仅负责展示数据;
  • 控制器负责接收用户请求,并调用模型(Service/Manger/DAO)来处理业务逻辑.模型可能会返回一些数据需要在视图层展示,控制器就需要整理模型数据并调用视图展示.

MVC模式的核心思想就是 将业务逻辑从界面中分离出来,允许它们单独改变而不会相互影响.

Spring MVC 实践 – Base

Spring MVC

Spring MVC框架是基于Java语言的MVC架构具体实现.他的设计围绕 DispatcherServlet 展开, DispatcherServlet 负责将请求分派给指定的 Controller ( Handler ),通过可配置的 HandlerMappingHandlAdapterControllerViewResolver处理请求 拿到数据并填充对应的视图 View :

Spring MVC 实践 – Base
组件 名称 描述
DispatcherServlet 调度器/前端控制器 DispatcherServlet前端控制器 模式的具体实现(详细可参考 Front Controller ),他提供了整个Web应用的集中访问点,截获请求并将其分派给指定的 Controller ,相当于MVC中的 C . 他的存在降低了组件之间的耦合性.
HandlerMapping 处理器映射器 HandlerMapping 负责根据用户请求 URI 找到对应的 ControllerInterceptor ,并将它们封装在 HandlerExecutionChain 中返回给 DispatcherServlet .
HandlAdapter 处理器适配器 Spring MVC通过 HandlerAdapter 执行 Controller ,这是 适配器模式 的应用,通过扩展适配器可以执行更多类型的 Controller .
Controller 处理器 Controller (又称 Handler )是继 DispatcherServlet 前端控制器之后的 后端控制器 ,在 DispatcherServlet 的控制下 Controller 对具体的用户请求进行处理.
ViewResolver 视图解析器 负责将 Model 数据填充到 View , 组合生成视图展示:他首先将 逻辑视图名 解析成 物理视图名 ,生成 View 视图对象,最后对 View 进行渲染(填充数据). Spring默认提供了针对JSP/Velocity/PFD等视图的 ViewResolver 实现.

初识Spring MVC

需求: 用户列表查询.

  • 创建Maven Web项目
mvn archetype:generate  -DgroupId=com.fq.mvc                          -DartifactId=MVC                          -DarchetypeArtifactId=maven-archetype-webapp                          -DinteractiveMode=false                          -DarchetypeCatalog=internal
  • 依赖管理

    在pom.xml中添加 SpringSpring MVC 、  SevletVelocity 依赖:

<!-- Spring --> <dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-core</artifactId>     <version>${spring.version}</version> </dependency> <dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-context</artifactId>     <version>${spring.version}</version> </dependency> <dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-context-support</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-expression</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-test</artifactId>     <version>${spring.version}</version> </dependency>  <!-- WEB --> <dependency>     <groupId>javax.servlet</groupId>     <artifactId>javax.servlet-api</artifactId>     <version>${servlet.version}</version> </dependency> <dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-webmvc</artifactId>     <version>${spring.version}</version> </dependency>  <!-- Velocity --> <dependency>     <groupId>org.apache.velocity</groupId>     <artifactId>velocity</artifactId>     <version>${velocity.version}</version> </dependency> <dependency>     <groupId>org.apache.velocity</groupId>     <artifactId>velocity-tools</artifactId>     <version>${velocity.tools.version}</version> </dependency>
  • 配置 DispatcherServlet (web.xml)
<?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>MVC</display-name>      <!-- 配置SpringMVC -->     <servlet>         <servlet-name>mvc</servlet-name>         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>         <init-param>             <!-- contextConfigLocation: 指定MVC配置文件位置 -->             <param-name>contextConfigLocation</param-name>             <param-value>classpath:spring/mvc-servlet.xml</param-value>         </init-param>         <load-on-startup>1</load-on-startup>     </servlet>     <servlet-mapping>         <!-- 拦截所有以.do结尾的URL -->         <servlet-name>mvc</servlet-name>         <url-pattern>*.do</url-pattern>     </servlet-mapping> </web-app>
  • 配置 HandlerMapping / HandlerAdapter (mvc-servlet.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"        xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans.xsd">      <!-- 处理器映射器 -->     <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>      <!-- 处理器适配器 -->     <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> </beans>
  • Controller
/**  * @author jifang  * @since 16/3/15 下午4:40.  */ public class UserController implements Controller {      @Override     public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {         List<User> users = new ArrayList<>();         users.add(new User(1, "翡青", new Date(), 1, "浙江-杭州"));         users.add(new User(2, "小芳", new Date(), 2, "山东-青岛"));          ModelAndView result = new ModelAndView();         result.addObject("users", users);         result.setViewName("users");         return result;     } }
<!-- 装配 Controller --> <bean name="/mvc/users.do" class="com.fq.mvc.controller.UserController"/>
  • 配置 ViewResolver (mvc-servlet.xml)

    由于我们视图选用的是 Velocity ,因此配置 VelocityViewResolver :

<!-- 配置视图解析器 --> <bean id="viewResolver"       class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">     <property name="suffix" value=".vm"/>     <property name="contentType" value="text/html;charset=UTF-8"/>     <property name="dateToolAttribute" value="dateTool"/>     <property name="numberToolAttribute" value="numberTool"/>     <property name="exposeRequestAttributes" value="false"/>     <property name="exposeSessionAttributes" value="true"/> </bean>  <!-- 配置Velocity --> <bean id="velocityConfigurer"       class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">     <!-- 设置VM模板放置位置-->     <property name="resourceLoaderPath" value="views"/>     <!-- 防止乱码 -->     <property name="velocityProperties">         <props>             <prop key="input.encoding">UTF-8</prop>             <prop key="output.encoding">UTF-8</prop>         </props>     </property> </bean>
  • View(/views/users.vm)
<html> <head>     <title>用户列表</title>     <link rel="stylesheet" href="/css/main.css">     <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> </head> <body> <div id="global">     <fieldset>         <legend>用户列表:</legend>          <table width="100%" border=0>             <tr>                 <td>ID</td>                 <td>username</td>                 <td>birthday</td>                 <td>sex</td>                 <td>address</td>             </tr>              #foreach($user in $users)                 <tr>                     <td>${user.id}</td>                     <td>${user.name}</td>                     <td>${user.birthday}</td>                     #if(${user.sex} == 1)                         <td>男</td>                     #else                         <td>女</td>                     #end                     <td>${user.address}</td>                 </tr>             #end         </table>     </fieldset> </div> </body> </html>

参考: main.css地址: OSChina

  • 前端控制器
    Spring MVC  DispatcherServleturl-pattern 有两种配置方式:
    • *.do : 拦截所有以 .do 结尾的URI.
    • /  : 拦截  所有  URI.
  • 处理器映射器
    BeanNameUrlHandlerMapping 指定将Bean的Name作为URI映射; Spring还提供了 SimpleUrlHandlerMapping 将URI和 Controller 的id统一映射配置.
  • 处理器适配器
    SimpleControllerHandlerAdapter 对所有实现了 Controller 接口的JavaBean适配.Spring还提供 HttpRequestHandlerAdapter 对所有实现了 HttpRequestHandler 接口的JavaBean适配.
  • 视图解析器
    前面使用 Velocity 作为视图展示,如果使用的是JSP的话, 需要配置另一种视图解析器 InternalResourceViewResolver :
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">     <!-- "JstlView"表示可以在JSP页面JSTL标签库,所以需要在项目中添加JSTL依赖 -->     <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>     <property name="prefix" value="/views"/>     <property name="suffix" value=".jsp"/> </bean>

注解初步

从2.5版本开始, Spring引入了注解开发:

  • 注解驱动(mvc-servlet.xml)
    • 从3.1版本开始,Spring MVC使用 RequestMappingHandlerMapping   注解式处理器映射器  对标有 @ResquestMapping 的方法进行 映射 .
    • 从3.1版本开始,Spring MVC使用 RequestMappingHandlerAdapter   注解式处理器适配器  对标记有 @ResquestMapping 的方法进行 适配 .
    • Spring MVC使用 <mvc:annotation-driven/>   注解驱动 自动加载 RequestMappingHandlerMappingRequestMappingHandlerAdapter 及其他相关配置. 因此在mvc-servlet.xml最简单有效的配置方式是使用 <mvc:annotation-driven/> 替代注解处理器和适配器:
<mvc:annotation-driven/>

尽管 <mvc:annotation-driven/> 很小, 但他具有足够的威力, 它注册了很多的特性, 包括对JSR-303校验、信息转换以及对域格式化的支持.

  • 组件扫描(mvc-servlet.xml):

    使用Spring的组件扫描来省去为每个 Controller 注册的麻烦:

<context:component-scan base-package="com.fq.mvc.controller"/>
  • 注解 Controller
@Controller @RequestMapping("/mvc") public class UserController {      @RequestMapping("/users.do")     public ModelAndView users() {         List<User> users = new ArrayList<>();         users.add(new User(1, "翡青", new Date(), 1, "浙江-杭州"));         users.add(new User(2, "小芳", new Date(), 2, "山东-青岛"));          ModelAndView result = new ModelAndView();         result.addObject("users", users);         result.setViewName("users");         return result;     } }

使用基于注解的`Controller`有以下优点: - 基于注解的`Controller`请求映射关系不存储在配置文件中,使用`@RequestMappeing`便可以对一个方法进行映射. - 一个`Controller`内可以有多个处理方法,可以响应多个动作,这样就允许将同一模块的多个操作写在同一个`Controller`里面,便于模块划分,且减少类的数量.

集成MyBatis

  • 通过Spring将各层整合:
    • 持久层DAO(MyBatis的Mapper)注册到Spring容器中.
    • 业务层Service/Manager从Spring容器中拿到DAO接口, 并注册Service服务.
    • 表现层Controller从Spring容器中拿到Service接口, 通过Spring MVC进行数据展示.
      Spring MVC 实践 – Base

需求: 展示所有用户数据(由于数据模型较简单, 因此从DAO到Controller只使用一个DO对象-User).

  • 依赖管理
<!-- Spring --> <dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-core</artifactId>     <version>${spring.version}</version> </dependency> <dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-context</artifactId>     <version>${spring.version}</version> </dependency> <dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-context-support</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-expression</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-test</artifactId>     <version>${spring.version}</version> </dependency>  <!-- AOP --> <dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-aop</artifactId>     <version>${spring.version}</version> </dependency> <dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-aspects</artifactId>     <version>${spring.version}</version> </dependency>  <!-- WEB --> <dependency>     <groupId>javax.servlet</groupId>     <artifactId>javax.servlet-api</artifactId>     <version>${servlet.version}</version> </dependency> <dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-webmvc</artifactId>     <version>${spring.version}</version> </dependency>  <!-- Velocity --> <dependency>     <groupId>org.apache.velocity</groupId>     <artifactId>velocity</artifactId>     <version>${velocity.version}</version> </dependency> <dependency>     <groupId>org.apache.velocity</groupId>     <artifactId>velocity-tools</artifactId>     <version>${velocity.tools.version}</version> </dependency>  <!-- DB --> <dependency>     <groupId>org.mybatis</groupId>     <artifactId>mybatis</artifactId>     <version>3.3.0</version> </dependency> <dependency>     <groupId>mysql</groupId>     <artifactId>mysql-connector-java</artifactId>     <version>${mysql.version}</version> </dependency> <dependency>     <groupId>com.zaxxer</groupId>     <artifactId>HikariCP</artifactId>     <version>${hikaricp.version}</version> </dependency>  <!-- Spring DB支持 --> <dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-jdbc</artifactId>     <version>${spring.version}</version> </dependency> <dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-tx</artifactId>     <version>${spring.version}</version> </dependency> <dependency>     <groupId>org.mybatis</groupId>     <artifactId>mybatis-spring</artifactId>     <version>${mybatis.spring.version}</version> </dependency>  <!-- log --> <dependency>     <groupId>ch.qos.logback</groupId>     <artifactId>logback-classic</artifactId>     <version>${logback.version}</version> </dependency>

集成MyBatis

  • mybatis-configuration.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"         "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration>     <mappers>         <mapper resource="mybatis/mapper/UserDAO.xml"/>     </mappers> </configuration>
  • domain: User
/**  * @author jifang.  * @since 2016/5/26 11:16.  */ public class User {      private int id;      private String name;      private Date birthday;      private int sex;      private String address;      public User() {     }      public User(int id, String name, Date birthday, int sex, String address) {         this.id = id;         this.name = name;         this.birthday = birthday;         this.sex = sex;         this.address = address;     }      public int getId() {         return id;     }      public void setId(int id) {         this.id = id;     }      public String getName() {         return name;     }      public void setName(String name) {         this.name = name;     }      public Date getBirthday() {         return birthday;     }      public void setBirthday(Date birthday) {         this.birthday = birthday;     }      public int getSex() {         return sex;     }      public void setSex(int sex) {         this.sex = sex;     }      public String getAddress() {         return address;     }      public void setAddress(String address) {         this.address = address;     } }
  • UserDAO
/**  * @author jifang  * @since 16/3/20 下午5:47.  */ public interface UserDAO {      List<User> selectAllUsers(); }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"         "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.fq.mvc.dao.UserDAO">      <select id="selectAllUsers" resultType="com.fq.mvc.domain.User">         SELECT *         FROM user;     </select>  </mapper>
  • applicationContext-datasource.xml(配置数据源)
<beans xmlns="http://www.springframework.org/schema/beans"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"        xmlns:context="http://www.springframework.org/schema/context"        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">      <context:property-placeholder location="classpath:db.properties"/>      <!-- 配置数据源 -->     <bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">         <property name="driverClassName" value="${mysql.driver.class}"/>         <property name="jdbcUrl" value="${mysql.url}"/>         <property name="username" value="${mysql.user}"/>         <property name="password" value="${mysql.password}"/>         <property name="maximumPoolSize" value="5"/>         <property name="maxLifetime" value="700000"/>         <property name="idleTimeout" value="600000"/>         <property name="connectionTimeout" value="10000"/>         <property name="dataSourceProperties">             <props>                 <prop key="dataSourceClassName">com.mysql.jdbc.jdbc2.optional.MysqlDataSource</prop>                 <prop key="cachePrepStmts">true</prop>                 <prop key="prepStmtCacheSize">250</prop>                 <prop key="prepStmtCacheSqlLimit">2048</prop>             </props>         </property>     </bean>      <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">         <constructor-arg ref="hikariConfig"/>     </bean>      <!-- 配置SqlSessionFactory -->     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">         <property name="dataSource" ref="dataSource"/>         <property name="configLocation" value="classpath:mybatis/mybatis-configuration.xml"/>     </bean>      <!-- 基于包扫描的mapper配置 -->     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">         <property name="basePackage" value="com.fq.mvc.dao"/>         <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>     </bean>      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">         <property name="dataSource" ref="dataSource"/>     </bean>  </beans>
  • db.properties
## Data Source mysql.driver.class=com.mysql.jdbc.Driver mysql.url=jdbc:mysql://host:port/db?characterEncoding=utf-8 mysql.user=user mysql.password=password

集成Service

public interface UserService {      List<User> getAllUsers(); }
@Service public class UserServiceImpl implements UserService {      @Autowired     private UserDAO dao;      @Override     public List<User> getAllUsers() {         return dao.selectAllUsers();     } }
  • applicationContext.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: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/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/tx   http://www.springframework.org/schema/tx/spring-tx.xsd   http://www.springframework.org/schema/aop   http://www.springframework.org/schema/aop/spring-aop.xsd">      <import resource="applicationContext-datasource.xml"/>      <context:component-scan base-package="com.fq.mvc.service"/>      <bean id="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="select*" timeout="-1" propagation="REQUIRED" read-only="true"/>         </tx:attributes>     </tx:advice>      <aop:config>         <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.fq.mvc.service.impl.UserServiceImpl.*(..))"/>     </aop:config>  </beans>

集成MVC

  • Controller
@Controller @RequestMapping("/mvc") public class UserController {      @Autowired     private UserService service;      @RequestMapping(value = "/user.do")     public ModelAndView users() {         List<User> users = service.getAllUsers();         return new ModelAndView("users", "users", users);     } }
  • mvc-servlet.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"        xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans.xsd   http://www.springframework.org/schema/mvc   http://www.springframework.org/schema/mvc/spring-mvc.xsd   http://www.springframework.org/schema/context   http://www.springframework.org/schema/context/spring-context.xsd">      <mvc:annotation-driven/>      <context:component-scan base-package="com.fq.mvc.controller"/>      <!-- 配置视图解析器 -->     <bean id="viewResolver"           class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">         <property name="suffix" value=".vm"/>         <property name="contentType" value="text/html;charset=UTF-8"/>         <property name="dateToolAttribute" value="dateTool"/>         <property name="numberToolAttribute" value="numberTool"/>         <property name="exposeRequestAttributes" value="false"/>         <property name="exposeSessionAttributes" value="true"/>     </bean>      <!-- 配置Velocity -->     <bean id="velocityConfigurer"           class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">         <!-- 设置VM模板放置位置-->         <property name="resourceLoaderPath" value="views"/>         <!-- 防止乱码 -->         <property name="velocityProperties">             <props>                 <prop key="input.encoding">UTF-8</prop>                 <prop key="output.encoding">UTF-8</prop>             </props>         </property>     </bean> </beans>
  • web.xml
<?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>MVC</display-name>      <!-- 加载Spring -->     <listener>         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>     </listener>     <context-param>         <param-name>contextConfigLocation</param-name>         <param-value>classpath:spring/applicationContext.xml</param-value>     </context-param>      <!-- 加载SpringMVC -->     <servlet>         <servlet-name>mvc</servlet-name>         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>         <init-param>             <param-name>contextConfigLocation</param-name>             <param-value>classpath:spring/mvc-servlet.xml</param-value>         </init-param>         <load-on-startup>1</load-on-startup>     </servlet>     <servlet-mapping>         <servlet-name>mvc</servlet-name>         <url-pattern>*.do</url-pattern>     </servlet-mapping> </web-app>
  • View视图同前

集成log

为了能够看到Spring MVC的 运行时信息 , 最好在应用中集成一种Log实现, 在此选用 LogBack :

  • logback.xml
<configuration>      <property name="log_root_dir" value="/data/logs/mvc/"/>     <property name="log_pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n"/>      <appender name="STD_OUT" class="ch.qos.logback.core.ConsoleAppender">         <encoder>             <pattern>${log_pattern}</pattern>         </encoder>     </appender>     <appender name="FILE_OUT" class="ch.qos.logback.core.rolling.RollingFileAppender">         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">             <fileNamePattern>${log_root_dir}/mvc-server.%d{YY-MM-dd}.log</fileNamePattern>             <maxHistory>7</maxHistory>         </rollingPolicy>         <encoder>             <pattern>${log_pattern}</pattern>         </encoder>     </appender>      <root level="DEBUG">         <appender-ref ref="STD_OUT"/>         <appender-ref ref="FILE_OUT"/>     </root>  </configuration>

注解开发

需求: 实现User添加.

  • add_user.vm
<html> <head>     <title>用户添加</title>     <link rel="stylesheet" href="/css/main.css">     <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> </head> <body> <div id="global">     <fieldset>         <legend>Add a User</legend>         <form action="/mvc/add_user.do" method="post">             <p>                 <label for="name">username: </label>                 <input type="text" name="name" tabindex="1">             </p>              <p>                 <label for="birthday">birthday: </label>                 <input type="text" name="birthday" tabindex="2"/>             </p>              <p>                 <label for="sex">sex: </label>                 <select name="sex" tabindex="3">                     <option value="1">男</option>                     <option value="2">女</option>                 </select>             </p>             <p>                 <label form="address">address: </label>                 <input type="text" name="address" tabindex="4">             </p>             <p id="buttons">                 <input type="reset" tabindex="5">                 <input type="submit" tabindex="6" value="Add User">             </p>         </form>     </fieldset> </div> </body> </html>
  • Controller
@RequestMapping("/add_user.do") public String addUser(User user){     service.addUser(user);     return "redirect: users.do"; }
  • Service/DAO实现简单,不再赘述.

请求参数解析

在传统的Servlet编程中, 可以使用 HttpServletRequestgetParameter() 方法来获取请求参数值, 而在Spring MVC中, 它会调用 请求参数解析组件 将客户端传过来的 String 字符串 解析为指定的 Java对象 并传递给 Controller , 这个过程称为 请求参数解析 .

Spring MVC默认提供了很多 参数解析组件 , 因此 Controller 的请求处理方法默认就可以接收很多不同类型:

JavaEE JavaSE Spring
ServletRequest / HttpServletRequest InputStreamReader WebRequestNativeWebRequest
ServletResponse / HttpServletResponse OutputStreamWriter ModelModelMap
HttpSession 命令或表单对象 (如 StringInteger / User ) RedirectAttributes
HttpEntity<?> ArrayListMap ErrorsBindingResult
@PathVariable@MatrixVariable 注解的对象 @RequestParam@RequestHeader@RequestBody / @RequestPart
PrincipalLocale SessionStatus
UriComponentsBuilder

注:

1. 如果 Controller 形参名与URI中 name 不一致, 可使用 @RequestParam 注解对其进行修饰.

2. Spring MVC还支持 路径变量映射 (路径变量类似于请求参数, 但没有key部分, 只是一个值, 详细可参考博客 Spring MVC URL 路径映射 ).

ModelAttribute

Spring MVC会在每次调用请求处理方法时都创建一个 Model 对象, 若打算使用该实例, 则可以在方法的形参添加一个 Model 形参. 其实还可以使用 @ModelAttribute 注解来访问 Model 实例: 使用 @ModelAttribute 注解标注参数或方法,该方法会将其输入的或创建的参数对象添加到 Model 对象中:

  • @ModelAttribute 标注形参
@RequestMapping("/check_id.do") public String checkId(@ModelAttribute("id") String id, Model model){     return "check_id"; }

String 实例将以 id 做key添加到 Model 对象中(如果key未命名,则默认使用类型的名称(如 string )做key).

  • @ModelAttribute 标注方法

    @ModelAttribute 的第二个用途是标注一个 非请求处理方法 : 被 @ModelAttribute 标注的方法会在每次调用 Controller 的请求处理方法时调用.该方法可以返回对象或 void :

如果返回对象, 该对象会自动添加到 Model 中:

@ModelAttribute private List<User> addUser() {     return service.getAllUsers(); }

若返回 void , 则必须添加一个 Model 类型参数, 自行将实例添加到 Model 中:

@ModelAttribute private void addUser(Model model) {     model.addAttribute("users", service.getAllUsers()); }

重定向与Flash属性

使用重定向的一个重要场景是 避免用户重新加载页面再次调用相同动作 . 比如 add_user.do : 当用户提交表单时会将用户信息插入数据库. 但如果在提交表单后重新加载页面,  add_user.do 会被再次调用, 相同的用户可能会被再次添加.为了避免这种情况, 最好的办法是在提交表单后将用户重定向到一个不同的页面,这个页面任意重新加载都没有副作用.

但使用重定向的一个不便之处在于: 无法轻松的给目标页面传值 . 如果采用转发, 可属性添加到 Model , 使得目标视图可以轻松访问. 但用户重定向需要经过客户端, 所以 Model 的一切内容都会在重定向中丢失. 幸运的是, 在Spring 3.1之后,可以通过 Flash 属性提供重定向传值的方法:

要使用Flash属性, 必须要有 <annotation-driven/> 注解驱动支持, 然后在方法上添加一个新的参数类型 RedirectAttributes :

@RequestMapping("/add_user.do") public String addUser(User user, RedirectAttributes attributes){     service.addUser(user);     attributes.addAttribute("message", "new user has been saved to DB.");     return "redirect: /views/message.vm"; }

Controller返回值

应用了 @Controller@RequestMapping 注解之后, Controller 不再需要 implements 特定的接口, 因此 Controller 的返回值也变得多种多样:

返回值 描述
ModelAndView 包含视图名与Model数据
Model
Map 包含模型的属性
View
String 代表逻辑视图名
void 可以在参数中传入request/response完成对参数的解析, 对客户端的响应
HttpEntity / ResponseEntity 提供对Servlet的访问, 以响应HTTP头部和内容
Callable
DeferredResult
其他任意类型 常与响应JSON/XML结合
原文  http://www.importnew.com/20774.html
正文到此结束
Loading...