MVC 定义:
MVC本质:
MVC的核心思想是:业务数据的抽取同业务数据的呈现相分离
VIEW:视图层,为用户提供UI重点关注数据的呈现
Model:模型层,业务数据的信息表示,关注支撑业务的信息构成,
通常是多个业务实体的组合。
Controller:控制层,调用业务逻辑产生适合的数据(Model)传递数据给视图层用于呈现
数据绑定
Binding 将请求中的字段按照名字匹配的原则填入模型对象。
SpringMVC 的核心——前端控制器
前端控制器是mvc的一种实现方式
动态模型
项目基本配置
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<!-- $Id: pom.xml 642118 2008-03-28 08:04:16Z reinhard $ -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<name>she</name>
<groupId>com.shan</groupId>
<artifactId>she</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-javac</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-compiler-api</artifactId>
<version>2.7</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.7</version>
<configuration>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>8888</port>
<maxIdleTime>30000</maxIdleTime>
</connector>
</connectors>
<webAppSourceDirectory>${project.build.directory}/${project.artifactId}-${project.version}
</webAppSourceDirectory>
<contextPath>/she</contextPath>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<commons-lang.version>2.6</commons-lang.version>
<slf4j.version>1.7.6</slf4j.version>
<spring.version>4.1.3.RELEASE</spring.version>
<jackson.version>2.5.4</jackson.version>
</properties>
<!--两个东西都依赖一个包但是可能有版本冲突的时候就要使用这个东西来进一步声明,使用这里指定的统一的版本-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons-lang.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
</project>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Spring MVC Study</display-name>
<!-- Spring应用上下文, 理解层次化的ApplicationContext -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/configs/spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- DispatcherServlet, Spring MVC的核心 -->
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- DispatcherServlet对应的上下文配置, 默认为/WEB-INF/$servlet-name$-servlet.xml
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/configs/spring/mvc-dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<!-- mvc-dispatcher拦截所有的请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
mvc-dispatcher-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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 本配置文件是工名为mvc-dispatcher的DispatcherServlet使用, 提供其相关的Spring MVC配置 -->
<!-- 启用Spring基于annotation的DI, 使用户可以在Spring MVC中使用Spring的强大功能。 激活 @Required
@Autowired,JSR 250's @PostConstruct, @PreDestroy and @Resource 等标注 -->
<context:annotation-config />
<!-- DispatcherServlet上下文, 只管理@Controller类型的bean, 忽略其他型的bean, 如@Service -->
<context:component-scan base-package="com.imooc.mvcdemo">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
<!-- HandlerMapping, 无需配置, Spring MVC可以默认启动。 DefaultAnnotationHandlerMapping
annotation-driven HandlerMapping -->
<!-- 扩充了注解驱动,可以将请求参数绑定到控制器参数 -->
<mvc:annotation-driven />
<!-- 静态资源处理, css, js, imgs -->
<mvc:resources mapping="/resources/**" location="/resources/" />
<!-- 配置ViewResolver。 可以用多个ViewResolver。 使用order属性排序。 InternalResourceViewResolver放在最后。 -->
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
<entry key="htm" value="text/html" />
</map>
</property>
<property name="defaultViews">
<list>
<!-- JSON View -->
<bean
class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
</bean>
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
</bean>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsps/" />
<property name="suffix" value=".jsp" />
</bean>
<!--200*1024*1024即200M resolveLazily属性启用是为了推迟文件解析,以便捕获文件大小异常 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="209715200" />
<property name="defaultEncoding" value="UTF-8" />
<property name="resolveLazily" value="true" />
</bean>
</beans>
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:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:annotation-config />
<!--因为 DispatcherServlet 负责管理 Controller 所以这里声明spring不管它-->
<context:component-scan base-package="com.imooc.mvcdemo">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
</beans>
CourseController.java
package com.imooc.mvcdemo.controller;
import com.imooc.mvcdemo.model.Course;
import com.imooc.mvcdemo.service.CourseService;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
@Controller
@RequestMapping("/courses")
// /courses/**
public class CourseController {
private static Logger log = LoggerFactory.getLogger(CourseController.class);
private CourseService courseService;
@Autowired
public void setCourseService(CourseService courseService) {
this.courseService = courseService;
}
//本方法将处理 /courses/view?courseId=123 形式的URL
@RequestMapping(value = "/view", method = RequestMethod.GET)
public String viewCourse(@RequestParam("courseId") Integer courseId,
Model model) {
log.debug("In viewCourse, courseId = {}", courseId);
Course course = courseService.getCoursebyId(courseId);
model.addAttribute(course);
return "course_overview";
}
//本方法将处理 /courses/view2/123 形式的URL
@RequestMapping("/view2/{courseId}")
public String viewCourse2(@PathVariable("courseId") Integer courseId,
Map<String, Object> model) {
log.debug("In viewCourse2, courseId = {}", courseId);
Course course = courseService.getCoursebyId(courseId);
model.put("course", course);
return "course_overview";
}
//本方法将处理 /courses/view3?courseId=123 形式的URL
@RequestMapping("/view3")
public String viewCourse3(HttpServletRequest request) {
Integer courseId = Integer.valueOf(request.getParameter("courseId"));
Course course = courseService.getCoursebyId(courseId);
request.setAttribute("course", course);
return "course_overview";
}
@RequestMapping(value = "/admin", method = RequestMethod.GET, params = "add")
public String createCourse() {
return "course_admin/edit";
}
@RequestMapping(value = "/save", method = RequestMethod.POST)
public String doSave(@ModelAttribute Course course) {
log.debug("Info of Course:");
log.debug(ReflectionToStringBuilder.toString(course));
//在此进行业务操作,比如数据库持久化
course.setCourseId(123);
return "redirect:view2/" + course.getCourseId();
}
@RequestMapping(value = "/upload", method = RequestMethod.GET)
public String showUploadPage(@RequestParam(value = "multi", required = false) Boolean multi) {
if (multi != null && multi) {
return "course_admin/multifile";
}
return "course_admin/file";
}
@RequestMapping(value = "/doUpload", method = RequestMethod.POST)
public String doUploadFile(@RequestParam("file") MultipartFile file) throws IOException {
if (!file.isEmpty()) {
log.debug("Process file: {}", file.getOriginalFilename());
FileUtils.copyInputStreamToFile(file.getInputStream(), new File("c:\\temp\\imooc\\", System.currentTimeMillis() + file.getOriginalFilename()));
}
return "success";
}
@RequestMapping(value = "/doUpload2", method = RequestMethod.POST)
public String doUploadFile2(MultipartHttpServletRequest multiRequest) throws IOException {
Iterator<String> filesNames = multiRequest.getFileNames();
while (filesNames.hasNext()) {
String fileName = filesNames.next();
MultipartFile file = multiRequest.getFile(fileName);
if (!file.isEmpty()) {
log.debug("Process file: {}", file.getOriginalFilename());
FileUtils.copyInputStreamToFile(file.getInputStream(), new File("c:\\temp\\imooc\\", System.currentTimeMillis() + file.getOriginalFilename()));
}
}
return "success";
}
@RequestMapping(value = "/{courseId}", method = RequestMethod.GET)
public
@ResponseBody
Course getCourseInJson(@PathVariable Integer courseId) {
return courseService.getCoursebyId(courseId);
}
@RequestMapping(value = "/jsontype/{courseId}", method = RequestMethod.GET)
public ResponseEntity<Course> getCourseInJson2(@PathVariable Integer courseId) {
Course course = courseService.getCoursebyId(courseId);
return new ResponseEntity<Course>(course, HttpStatus.OK);
}
}
注意:文件上传表单的构成要素
<form method="post" action="/courses/doUpload" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit"/>
</form>
如何在 SpringMVC 中处理 JSON
SpringMVC用ContentNegotiatingViewResolver (配置见:mvc-dispatcher-servlet.xml)来处理相同信息的不同处理和呈现 对机器Client
SpringMVC会使用 JsonView 因为机器需要的是Json 形式的信息; 对人类Client JSPView 呈现 HTML
页面来向用户传递信息。ContentNegotatingViewResolver:将服务器端相同的数据,根据不同的数据呈现请求,转化为不同的数据格式
ResoibseEntity : 将返回数据转换为 JSON 形式
@ResponseBody/ @RequestBody返回或者获取JSON 格式的信息。
Controller 部分的代码
@RequestMapping(value = "/{courseId}", method = RequestMethod.GET)
public
@ResponseBody
Course getCourseInJson(@PathVariable Integer courseId) {
return courseService.getCoursebyId(courseId);
}
@RequestMapping(value = "/jsontype/{courseId}", method = RequestMethod.GET)
public ResponseEntity<Course> getCourseInJson2(@PathVariable Integer courseId) {
Course course = courseService.getCoursebyId(courseId);
return new ResponseEntity<Course>(course, HttpStatus.OK);
}
使用 Controller 获取 JSON 格式响应信息异步呈现页面信息
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>我不是真正的慕课网</title>
<link rel="stylesheet"
href="<%=request.getContextPath()%>/resources/css/main.css"
type="text/css" />
<script type="text/javascript"
src="<%=request.getContextPath()%>/resources/js/jquery-1.11.3.min.js"></script>
</head>
<script>
jQuery(function($){
var urlStr = "<%=request.getContextPath()%>/courses/<%=request.getParameter("courseId")%>";
//alert("Before Call:"+urlStr);
$.ajax({
method: "GET",
url: urlStr,
success:function(data,status,jqXHR){
//alert("Success:"+data);
var course = data;
var path = "<%=request.getContextPath()%>/";
$(".course-title").html(course.title);
$(".course_video").attr("src", path+course.imgPath);
$("#learningNum").text(course.learningNum);
$("#duration").text(course.duration);
$("#levelDesc").text(course.levelDesc);
$(".course_shortdecription").html(course.descr);
var chapterList = course.chapterList;
var chapter;
for(var i = 0;i<chapterList.length;i++){
chapter = chapterList[i];
var liObj = $("li",$("#chapterTemplate")).clone();
$(".outline_name", liObj).text(chapter.title);
$(".outline_descr", liObj).text(chapter.descr);
liObj.appendTo("#couList");
}// ~ end for
}
}); // end ajax
});
</script>
<body>
<div id="main">
<div class="newcontainer" id="course_intro">
<div class="course-title"></div>
<div class="course_info">
<div class="course-embed l">
<div id="js-course-img" class="img-wrap">
<img width="600" height="340" alt=""
class="course_video" />
</div>
<div id="js-video-wrap" class="video" style="display: none">
<div class="video_box" id="js-video"></div>
</div>
</div>
<div class="course_state">
<ul>
<li><span>学习人数</span> <em id="learningNum"></em></li>
<li class="course_hour"><span>课程时长</span> <em
class="ft-adjust"><span id="duration"></span>秒</em></li>
<li><span>课程难度</span> <em id="levelDesc"></em></li>
</ul>
</div>
</div>
<div class="course_list">
<div class="outline">
<h3 class="chapter_introduces">课程介绍</h3>
<div class="course_shortdecription"></div>
<h3 class="chapter_catalog">课程提纲</h3>
<ul id="couList">
</ul>
</div>
</div>
</div>
</div>
<div id="chapterTemplate" style="display:none">
<li class="clearfix open"><a href="#">
<div class="openicon"></div>
<div class="outline_list l">
<h5 class="outline_name"></h5>
<p class="outline_descr"></p>
</div>
</a></li>
</div>
</body>
</html>