说明:本文章的内容转载至:https://my.oschina.net/happyBKs/blog/420310
如有侵权的地方,请联系本人,本人将会立即删除!
本文我们在前文基础上引入一个例子,边做边聊控制器。
我们想实现一个课程查询的功能。
首先大脑应该条件反射——如何定义MVC。
M:课程(包含章节)——Course(包含Chapter)
V:课程页面——course_overview.jsp
C:编写一个控制器接收springMVC前端控制器dispatcherServlet的请求转发——CourseController
另外,Service——一些业务逻辑调用——业务接口CourseService,业务实现CourseServiceImpl
然后,在思考如何在springMVC下组织上述各个部分。
C控制器是M、V、Service的中间桥梁,如何组织都是围绕着C展开的。
请求URL由springMVC前端控制器dispatcherServlet转发给控制器C——在web.xml配置dispatcherServlet,给出前端控制器配置文件路径
如何标记控制器C——配置前端控制器配置文件,定义搜索包范围空间、激活注解;在类定义的地方为类添加控制器注解
如何将URL请求与控制器之间建立映射——RequestMapping注解控制器类和方法
控制器C调用Service业务逻辑——在控制器类相应方法中调用Service接口方法;Service被控制器C所关联,控制器C中的Service属性引用需要用spring的依赖注入的方式完成初始化,所以要配置spring容器(一是要在web.xml配置spring,指明spring容器配置文件路径;二是在spring容器配置文件中配置好这些bean,本文的示例采用注解方法)
控制器C与视图V建立映射——前端控制器配置文件配置ViewResolver(定义前缀和后缀);控制器类的对应的接收请求的方法返回字符串;拼接出webapp下的资源路径字符串。
以上我通过两两关系描述了几部分是如何组织起来的,各种配置分别解决哪一个两两关系。好,我们直接进入项目来看。
首先是定义M、V、C、Service几个部分:
M部分:
Course:
package com.happyBKs.model;
import java.util.List;
public class Course {
// 课程Id
private Integer courseId;
// 课程名称
private String title;
// 图片路径
private String imgPath;
// 学习人数
private Integer learningNum;
// 课程时长
private Long duration;
// 课程难度
private Integer level;
// 课程难度描述
private String levelDesc;
// 课程介绍
private String descr;
// 课程提纲
private List chapterList;
public Integer getCourseId() {
return courseId;
}
public void setCourseId(Integer courseId) {
this.courseId = courseId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Integer getLearningNum() {
return learningNum;
}
public void setLearningNum(Integer learningNum) {
this.learningNum = learningNum;
}
public Integer getLevel() {
return level;
}
public void setLevel(Integer level) {
this.level = level;
}
public String getImgPath() {
return imgPath;
}
public void setImgPath(String imgPath) {
this.imgPath = imgPath;
}
public List getChapterList() {
return chapterList;
}
public void setChapterList(List chapterList) {
this.chapterList = chapterList;
}
public Long getDuration() {
return duration;
}
public void setDuration(Long duration) {
this.duration = duration;
}
public String getDescr() {
return descr;
}
public void setDescr(String descr) {
this.descr = descr;
}
public String getLevelDesc() {
return levelDesc;
}
public void setLevelDesc(String levelDesc) {
this.levelDesc = levelDesc;
}
}
Chapter:
package com.happyBKs.model;
public class Chapter {
private Integer id;
private Integer courseId;
private Integer order;
private String title;
private String descr;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getCourseId() {
return courseId;
}
public void setCourseId(Integer courseId) {
this.courseId = courseId;
}
public Integer getOrder() {
return order;
}
public void setOrder(Integer order) {
this.order = order;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescr() {
return descr;
}
public void setDescr(String descr) {
this.descr = descr;
}
}
V:
\src\main\webapp\WEB-INF\jsps\course_overview.jsp
<%@ page language="java"
contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!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>HappyBKs喜欢原先的osc博客页面</title>
<link rel="stylesheet"
href="<%=request.getContextPath()%>/resources/css/main.css"
type="text/css" />
</head>
<body>
<div id="main">
<div class="newcontainer" id="course_intro">
<div class="course-title">${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=""
src="<%=request.getContextPath()%>/${course.imgPath}"
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>${course.learningNum }</em></li>
<li class="course_hour"><span>课程时长</span> <em
class="ft-adjust"><span>${course.duration }</span>秒</em></li>
<li><span>课程难度</span> <em>${course.levelDesc }</em></li>
</ul>
</div>
</div>
<div class="course_list">
<div class="outline">
<h3 class="chapter_introduces">课程介绍</h3>
<div class="course_shortdecription">${course.descr}</div>
<h3 class="chapter_catalog">课程提纲</h3>
<ul id="couList">
<c:forEach items="${course.chapterList}" var="chapter">
<li class="clearfix open"><a href="#">
<div class="openicon"></div>
<div class="outline_list l">
<!-- <em class="outline_zt"></em> -->
<h5 class="outline_name">${chapter.title }</h5>
<p class="outline_descr">${chapter.descr }</p>
</div>
</a></li>
</c:forEach>
</ul>
</div>
</div>
</div>
</div>
</body>
</html>
值得注意的是,这里的href=”<%=request.getContextPath()%>/resources/css/main.css”这里url资源路径中的resources/**会在前端控制器配置文件中被配置映射到webapp项目资源路径。
这个后面会有详细的配置文件。
另外,jsp页面中的EL表达式中course,其名称也与控制器类中的相关参数和配置相对应。
Service:
业务模块部分都是讲接口调用和业务实现分类的。一个接口对应一个实现。
CourseService
package com.happyBKs.service;
import com.happyBKs.model.Course;
import org.springframework.stereotype.Service;
@Service
public interface CourseService {
Course getCoursebyId(Integer courseId);
}
CourseServiceImpl
package com.happyBKs.service.impl;
import java.util.ArrayList;
import java.util.List;
import com.happyBKs.model.Chapter;
import com.happyBKs.model.Course;
import com.happyBKs.service.CourseService;
import org.springframework.stereotype.Service;
@Service("courseService")
public class CourseServiceImpl implements CourseService {
public Course getCoursebyId(Integer courseId) {
Course course = new Course();
course.setCourseId(courseId);
course.setTitle("springMVC笔记系列");
course.setImgPath("resources/imgs/course-img.jpg");
course.setLearningNum(12345);
course.setLevel(2);
course.setLevelDesc("中级");
course.setDuration(7200l);
course.setDescr("springMVC哈哈哈哈。");
List<Chapter> chapterList = new ArrayList<Chapter>();
warpChapterList(courseId,chapterList);
course.setChapterList(chapterList);
return course;
}
private void warpChapterList(Integer courseId,List<Chapter> chapterList) {
Chapter chapter = new Chapter();
chapter.setId(1);
chapter.setCourseId(courseId);
chapter.setOrder(1);
chapter.setTitle("第1章 什么springMVC");
chapter.setDescr("此处略去1个字");
chapterList.add(chapter);
chapter = new Chapter();
chapter.setId(2);
chapter.setCourseId(courseId);
chapter.setOrder(2);
chapter.setTitle("第2章 环境搭建");
chapter.setDescr("此处略去2个字");
chapterList.add(chapter);
chapter = new Chapter();
chapter.setId(3);
chapter.setCourseId(courseId);
chapter.setOrder(3);
chapter.setTitle("第3章 前端控制器");
chapter.setDescr("此处略去3个字");
chapterList.add(chapter);
chapter = new Chapter();
chapter.setId(4);
chapter.setCourseId(courseId);
chapter.setOrder(4);
chapter.setTitle("第4章 spring上下文环境配置");
chapter.setDescr("此处略去4个字");
chapterList.add(chapter);
chapter = new Chapter();
chapter.setId(5);
chapter.setCourseId(courseId);
chapter.setOrder(5);
chapter.setTitle("第5章 示例");
chapter.setDescr("此处略去5个字");
chapterList.add(chapter);
}
}
控制器C:
好好好,终归到了几个部分的中心环节了。CourseController类是控制器类,用@Controller注解。其类和方法注解@RequestMapping,实现请求url到控制器类的映射。当然控制器类的相应方法会返回相关字符串,与前端控制器配置文件\WEB-INF\configs\spring\mvc-dispatcher-servlet.xml中的项目视图资源映射,即这里映射到\WEB-INF\jsps\course_overview.jsp
CourseController
package com.happyBKs.controller;
import com.happyBKs.model.Course;
import com.happyBKs.service.CourseService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Created by happyBKs on 2016/6/15.
*/
@Controller
@RequestMapping("/courses")
// /courses/**
public class CourseController {
//完成日志信息
private static Logger log= LoggerFactory.getLogger(CourseController.class);
private CourseService courseService;
//使用spring容器管理里了对应的依赖关系
@Autowired
public void setCourseService(CourseService courseService) {
this.courseService = courseService;
}
//提供完成一个业务的方法:根据课程ID查询课程内容。
//本方法将处理 /courses/view?courseId=123 形式的URL
@RequestMapping(value="/view", method= RequestMethod.GET)
public String viewCourse(@RequestParam("courseId") Integer courseId,
Model model) {
//日志输出,查看请求的courseId是不是我们的courseId
log.debug("In viewCourse, courseId = {}", courseId);
Course course = courseService.getCoursebyId(courseId);
model.addAttribute(course);
return "course_overview";
}
}
在这个控制器类中,我们注入了一个Service。Service和控制器C之间存在依赖,我们使用spring依赖注入Service的实现类对象,使用的自动化注入成员变量引用某个具体的bean,用@Autowired注解,相应的被注解的业务实现类需要标注@Service,并且,spring配置文件的搜索包空间必须包含它。
另外,本控制器类中增加了一个日志工具,帮助我们记录下执行步骤和信息。因为需要用slf4j中的log相关类型。所以我们需要重新对pom.xml增加一些jar的依赖坐标。
pom.xml
<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>
<groupId>testIdea.happBKs.mvc</groupId>
<artifactId>springMVC</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>springMVC Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<commons-lang.version>2.6</commons-lang.version>
<slf4j.version>1.7.21</slf4j.version>
<spring.version>4.2.6.RELEASE</spring.version>
<jackson.version>2.7.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>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<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>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<build>
<finalName>springMVC</finalName>
</build>
</project>
还需要一log的配置文件:
注意,这个配置文件属于源代码的配置文件,与webapp的配置文件不同,所以这里所处的resouces文件夹其实不同的一个,特别注意!!
log4j.appender.Cons=org.apache.log4j.ConsoleAppender
log4j.appender.Cons.layout=org.apache.log4j.PatternLayout
log4j.appender.Cons.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
# Root logger set to DEBUG using the A2 appender defined above.
log4j.rootLogger=info, Cons
log4j.additivity=false
#Application Logger+
log4j.logger.com.imooc.mvcdemo=debug, Cons
log4j.logger.org.springframework=debug, Cons
log4j.additivity.com=false
springMVC的配置文件\WEB-INF\configs\spring\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.happyBKs.controller">
<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>
spring容器配置文件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 />
<context:component-scan base-package="com.happyBKs">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
</beans>
另外需要一些css文件和js文件,这个不细说。
最后请求的结果如下: