Spring MVC 实践 - Base

Spring MVC 实践

标签 : Java与Web


Spring Web MVC

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


MVC

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

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

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


Spring MVC

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

组件 名称 描述
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 MVCSevletVelocity依赖:

<!-- 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进行数据展示.

    需求: 展示所有用户数据(由于数据模型较简单, 因此从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 InputStream / Reader WebRequest / NativeWebRequest
ServletResponse / HttpServletResponse OutputStream / Writer Model / ModelMap
HttpSession 命令或表单对象 (如String / Integer / User) RedirectAttributes
HttpEntity<?> Array / List / Map Errors / BindingResult
@PathVariable / @MatrixVariable注解的对象 @RequestParam / @RequestHeader / @RequestBody / @RequestPart
Principal / Locale 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结合

时间: 2024-10-13 11:50:17

Spring MVC 实践 - Base的相关文章

Spring MVC 实践笔记

1.先看下 Eclipse 中安装 maven 没有.没安装执行第 2 步.安装了执行第 3 步. 2.在 Eclipse EE 中在线安装 maven:Help-->Install New Software,HTTP地址:http://download.eclipse.org/technology/m2e/releases/ ,此处耗时很久,且中途易出错. 3.下载 apache-maven-3.3.3-bin.zip :http://maven.apache.org/download.cgi

IntelliJ IDEA:Getting Started with Spring MVC, Hibernate and JSON实践

最近把编辑器换成IntelliJ IDEA,主要是Eclipse中处理Maven项目很不方便,很早就听说IntelliJ IDEA的大名了,但是一直没机会试试.最近终于下载安装了,由于是新手,决定尝试个Tutorials,最终找了个熟悉点的项目,就是Getting Started with Spring MVC, Hibernate and JSON(http://confluence.jetbrains.com/display/IntelliJIDEA/Getting+Started+with

JSR-303 Bean Validation 介绍及 Spring MVC 服务端验证最佳实践

任何时候,当要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情. 应用程序必须通过某种手段来确保输入参数在上下文来说是正确的. 分层的应用在很多时候,同样的数据验证逻辑会出现在不同的层,这样就会导致代码冗余和一些管理的问题. 为了避免这样或那样的情况发生,最好是将验证逻辑与相应的数据模型进行绑定. 1. JSR-303 Bean Validation JSR 是Java Specification Requests 的缩写,是指向 JCP(Java Community Proces

Spring Boot 实践折腾记(五):自定义配置,扩展Spring MVC配置并使用fastjson

每日金句 专注和简单一直是我的秘诀之一.简单可能比复杂更难做到:你必须努力理清思路,从而使其变得简单.但最终这是值得的,因为一旦你做到了,便可以创造奇迹.--源自乔布斯 题记 前两天有点忙,没有连续更新,今天接着聊.金句里老乔的话说得多好,但能真正做到的人又有多少?至少就我个人而言,我还远远没有做到这样,只是一个在朝着这个方向努力的人,力求简明易懂,用大白话让人快速的明白理解,简单的例子上手,让使用的人更多的去实战使用扩展,折腾记即是对自己学习使用很好的一次总结,对看的人也是一个参考的方法,希望

基于Spring + Spring MVC + Mybatis + shiro 高性能web构建

一直想写这篇文章,前段时间 痴迷于JavaScript.NodeJs.AngularJS,做了大量的研究,对前后端交互有了更深层次的认识. 今天抽个时间写这篇文章,我有预感,这将是一篇很详细的文章,详细的配置,详细的注释,看起来应该很容易懂. 用最合适的技术去实现,并不断追求最佳实践.这就是架构之道. 希望这篇文章能给你们带来一些帮助,同时希望你们可以为这个项目贡献你的想法. 源码地址:https://github.com/starzou/quick4j 点击打开 看我们的项目结构: 是一个典型

[转]基于Spring + Spring MVC + Mybatis 高性能web构建

http://blog.csdn.net/zoutongyuan/article/details/41379851/ 一直想写这篇文章,前段时间 痴迷于JavaScript.NodeJs.AngularJs,做了大量的研究,对前后端交互有了更深层次的认识. 今天抽个时间写这篇文章,我有预感,这将是一篇很详细的文章,详细的配置,详细的注释,看起来应该很容易懂. 用最合适的技术去实现,并不断追求最佳实践.这就是架构之道. 希望这篇文章能给你们带来一些帮助,同时希望你们可以为这个项目贡献你的想法. 源

基于Spring + Spring MVC + Mybatis 高性能web构建

一直想写这篇文章,前段时间 痴迷于JavaScript.NodeJs.AngularJs,做了大量的研究,对前后端交互有了更深层次的认识. 今天抽个时间写这篇文章,我有预感,这将是一篇很详细的文章,详细的配置,详细的注释,看起来应该很容易懂. 用最合适的技术去实现,并不断追求最佳实践.这就是架构之道. 希望这篇文章能给你们带来一些帮助,同时希望你们可以为这个项目贡献你的想法. 源码地址:https://github.com/starzou/quick4j 点击打开 看我们的项目结构: 是一个典型

在Spring MVC中使用Apache Shiro安全框架

我们在这里将对一个集成了Spring MVC+Hibernate+Apache Shiro的项目进行了一个简单说明.这个项目将展示如何在Spring MVC 中使用Apache Shiro来构建我们的安全框架. [TOC] 阅读文章前,您需要做以下准备: Maven 3环境Mysql-5.6+JDK1.7+git环境git.oschina.net帐号Apache Tomcat 7+您熟练掌握的编辑工具,推荐使用InterlliJ IDEA 14+开始项目地址git.oschina.net 项目地

Spring MVC 学习笔记(二):@RequestMapping用法详解

一.@RequestMapping 简介 在Spring MVC 中使用 @RequestMapping 来映射请求,也就是通过它来指定控制器可以处理哪些URL请求,相当于Servlet中在web.xml中配置 <servlet>     <servlet-name>servletName</servlet-name>     <servlet-class>ServletClass</servlet-class> </servlet>