Spring MVC 实践 - Base
Posted 菜鸟-翡青
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
),通过可配置的HandlerMapping
、HandlAdapter
、Controller
、ViewResolver
来处理请求拿到数据并填充对应的视图View:
组件 | 名称 | 描述 |
---|---|---|
DispatcherServlet |
调度器/前端控制器 | DispatcherServlet 是前端控制器模式的具体实现(详细可参考Front Controller),他提供了整个Web应用的集中访问点,截获请求并将其分派给指定的Controller ,相当于MVC中的C . 他的存在降低了组件之间的耦合性. |
HandlerMapping |
处理器映射器 | HandlerMapping 负责根据用户请求URI 找到对应的Controller 与Interceptor ,并将它们封装在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中添加Spring、Spring MVC、 Sevlet及Velocity依赖:
<!-- 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 MVCDispatcherServlet
的url-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/>
注解驱动自动加载RequestMappingHandlerMapping
和RequestMappingHandlerAdapter
及其他相关配置. 因此在mvc-servlet.xml最简单有效的配置方式是使用<mvc:annotation-driven/>
替代注解处理器和适配器:
- 从3.1版本开始,Spring MVC使用
<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
以上是关于Spring MVC 实践 - Base的主要内容,如果未能解决你的问题,请参考以下文章
Spring MVC 3.2 Thymeleaf Ajax 片段
JSR-303 Bean Validation 介绍及 Spring MVC 服务端验证最佳实践
ehcache 或 Spring MVC 的 Spring 缓存中的最佳缓存实践是啥?
确保 AUTHENTICATED 用户被授权访问资源的最佳实践 - Spring mvc、Spring Security、Hibernate