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/javaeehttp://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/beanshttp://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 {@Overridepublic 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://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 {@Autowiredprivate UserDAO dao;@Overridepublic 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsdhttp://www.springframework.org/schema/aophttp://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 {@Autowiredprivate 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/contexthttp://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/javaeehttp://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结合

Spring MVC 实践 - Base相关推荐

  1. Spring MVC 实践 - Component

    Spring MVC 实践 标签 : Java与Web Converter Spring MVC的数据绑定并非没有任何限制, 有案例表明: Spring在如何正确绑定数据方面是杂乱无章的. 比如: S ...

  2. Spring MVC 实践笔记

    1.了解 Maven 的用法:http://spring.io/guides/gs/maven/ .这篇英文非常详细的演示了 Maven 的用法,在命令行下执行.注意,运行Maven的时候,Maven ...

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

    任何时候,当要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情. 应用程序必须通过某种手段来确保输入参数在上下文来说是正确的. 分层的应用在很多时候,同样的数据验证逻辑会出现在不同的层, ...

  4. spring mvc xss html,note/SpringMvc防御XSS实践.md at master · yangc91/note · GitHub

    SpringMvc防御XSS实践 项目在漏洞扫描时发现xss漏洞, 本以为是常见漏洞,网上有很多解决方案,应该能很快搞定,但实际上文章看了不少,却并未找到十分"顺手"的解决方案. ...

  5. 搭建Spring4+Spring MVC web工程的最佳实践

     Spring是个非常非常非常优秀的java框架,主要是用它的IOC容器帮我们依赖注入和管理一些程序中的Bean组件,实现低耦合关联,最终提高系统可扩展性和可维护性,用它来辅助我们构建web工程将 ...

  6. springboot templates读取不到_整合spring mvc + mybatis,其实很简单,spring boot实践(5)

    01 spring boot读取配置信息 02 多环境配置 03 处理全局异常 04 spring boot admin 主要通过spring boot整合spring mvc 以及mybatis实现 ...

  7. 看透 Spring MVC 源代码分析与实践 —— 俯视 Spring MVC

    Spring MVC Spring MVC 之初体验 环境搭建 在 IDEA 中新建一个 web 项目,用 Maven 管理项目的话,在 pom.xml 中加入 Spring MVC 和 Servle ...

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

    我们在这里将对一个集成了Spring MVC+Hibernate+Apache Shiro的项目进行了一个简单说明.这个项目将展示如何在Spring MVC 中使用Apache Shiro来构建我们的 ...

  9. Spring MVC防御CSRF、XSS和SQL注入攻击

    本文说一下SpringMVC如何防御CSRF(Cross-site request forgery跨站请求伪造)和XSS(Cross site script跨站脚本攻击). 说说CSRF 对CSRF来 ...

最新文章

  1. python开发环境安装
  2. 简易数字频率计(verilog HDL设计)(2020维护版本)
  3. 洛谷 P1516 青蛙的约会
  4. 这是从云栖大会指挥部发回的现场报道
  5. 关于SAP CRM中间件系统搭建中遇到的一些问题
  6. Mysql对字符串去掉前后空格(trim)或者指定字符
  7. kernel module required key not available
  8. java 多重注解_Java注解-元数据、注解分类、内置注解和自定义注解
  9. loadrunner——关联
  10. C Programming Style 总结
  11. apple 苹果官方的demo 下载地址
  12. java 中rest,Java中的REST调用
  13. Servlet学习笔记
  14. 内存屏障 Memery Barrier
  15. JS将字符串转数组、转数字、转对象;将数组转字符串、转对象;将对象转数组、转字符串
  16. c#教程之通过数据绑定修改数据
  17. 桥接,NAT,Host Only的区别
  18. @components问题
  19. 怎样在php中制作电子相册,免费电子相册制作软件 怎样把照片制作成电子相册并加背景音乐?...
  20. oralc 中图片的存储与读取

热门文章

  1. 操作系统之进程管理:8、进程互斥的软件实现方法(单标志、双标志、Peterson)
  2. Linux系统编程11:进程入门之详细阐述进程的一些状态区分僵尸状态和孤儿状态动图演示
  3. 215.数组中的第K个最大元素/347. 前 K 个高频元素
  4. zmq 接口函数之 :zmq_socket_monitor - 注册一个监控回调函数
  5. Android Studio 3.1.4 报错Failed to find style 'coordinatorLayoutStyle' in current theme
  6. 【线性代数】2-5:逆(Inverse)
  7. c#计算 坐标点与坐标点之间的距离
  8. netty 发送 http请求
  9. createPattern() 自定义宽高
  10. start running 开始跑步减肥