Spring MVC起步
1. MVC概念
1.1 前端控制器
1.2 MVC概念 MVC的核心思想---业务数据抽取 与 业务数据呈现 相分离
View:视图层,为用户提供UI,重点关注数据的呈现; Model:模型层,业务数据的信息表示,关注支撑业务地信息构成,通常是多个业务实体的组合; Cotroller:控制层,调用业务逻辑产生合适的数据,传递数据给视图层用于呈现;
MVC是什么?
1、MVC是一种架构模式,是程序分成,分工合作,既相互独立,有协同工作。
2、MVC是一种思考方式,模型层思考为用户展现什么,在视图层思考如何布局,在控制层思考调用那些业务逻辑。
2. Spring MVC概念
2.1 Spring MVC 基本概念
1、DispatcherServlet: 前端控制器
2、Controller: 调用业务逻辑生成model的地方
3、HandlerAdapter:处理器适配器DispatcherServlet通过HandlerAdapter调用controller
4、HandlerInterceptor:处理器拦截器 该接口提供after postHandle preHandle 三个方法,调用controller前后使用
5、HandlerMapping:前端控制器与controller映射关系的类
6、HandlerExecutionChain: preHandle->Controller method->postHandle->afterCompletion的执行链
7、ModelAndView:model的具体表现
8、ViewResolver:视图解析器,决定需要用哪个视图来进行视图的呈现。
2.2 架构流程图
2.3 架构流程
1、 用户发送请求至前端控制器DispatcherServlet
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
5、 执行处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9、 ViewReslover解析后返回具体View
10、 DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
11、 DispatcherServlet响应用户
3. 应用maven工具,管理springMVC
3.1 maven的三个重要概念:配置pom.xml,依赖dependency, 坐标coordinates(groupId,artifactId,version,packaging)
3.2 maven配置 setting.xml配置镜像仓库:用UK的镜像仓库可以提高访问成功率
镜像配置,每次访问Maven时候都先访问配置的这个库,下载所需要的软件包,这样可以降低中心仓库的负载,中心仓库为了避免大量访问造成的服务问题有时会拒绝
我们的访问。
3.3 Maven创建项目
3.3.1. 添加Maven 在继承Maven的eclipse中,windows--->prefrences---->Maven--->Installation--->将新下载的maven文件add进去,确保在user Setings中配置文件的路径是之前配置了mirror的配置文件setting.xml
3.3.2. 运行命令行创建项目 注意:需要在命令行中进入指定创建项目的路径 例如:cd C:\Users\Workspaces\Eclipse
命令: mvn archetype:generate -DgroupId=imooc-arthur -DartifactId=spring-mvc-study -DarchetypeArtifactId=maven-archetype-webapp
参数解释: archetype:generate 调用插件
groupId:坐标
artifactId:坐标的一个元素,目录结构的根目录名称
archetypeArtifactId:目录类型的一个类型,此为webapp的类型
3.3.3 搭建Spring MVC基础框架
1.导入项目 import-->Maven(ExistingMaven Projects)-->刚创建的文件目录spring-mvc-study
2.缺失Java目录时,手动添加Java目录 右键main-->folder-->java
3.pom.xml 添加各种依赖包
4.web.xml文件 配置 DispatcherServlet -- Spring MVC的核心
如果不配置<init-param>,那么将会默认读取WEB-INF目录下的%servlet-name%-servlet.xml配置文件,配置init-param后将读取这里配置的文件
5.mvc-dispatcher-servlet.xml 启用Spring基于annotation的DI 配置DispatcherServlet上下文, 只管理@Controller类型的bean, 忽略其他型的bean, 如@Service 扩充了注解驱动,可以将请求参数绑定到控制器参数 配置ViewResolver;可以用多个ViewResolver;使用order属性排序;InternalResourceViewResolver放在最后。
6.创建Controller类
7.创建home.jsp
8.运行jetty(在配置文件中配置的jetty插件为我们提供了一个运行的容器环境),访问
4. 在具体项目中实现springMVC
4.1 配置文件
4.1.1 在web.xml文件中如此配置
<!-- Spring应用上下文, 理解层次化的ApplicationContext --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/configs/spring/applicationContext*.xml</param-value> </context-param>
<!-- 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>
通过使用不同的dispatcher-servlet来做不同的分发,可以更好的服务不同来源的请求。
4.1.2 配置名为mvc-dispatcher的DispatcherServlet,为其提供spring MVC配置
mvc-dispatcher-servlet.xml文件中
<beans> xmlns=········ ············································省略.. <!-- 本配置文件是供名为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.zang.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> </beans>
4.1.3 配置applicationContext.xml
<context:annotation-config /> <context:component-scan base-package="com.zang.mvcdemo"> <!-- context:exclude-filter:不需要管理Controller了 --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan>
4.2 Controller代码
@Controller声明了一个Controller @RequestMapping对应到具体的请求 @RequestParam 和@PathVariable绑定了请求中的参数 也可以使用HttpServletRequest 或HttpSession请求响应
@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"; } }
4.3 Binding——绑定(将请求中的字段按照名字匹配的原则填入模型对象))
@RequestMapping中也可以添加params="add"属性,表示带add参数的请求才可以进来;返回字符串可以加/来进行相对目录的指定。
@ModelAttribute可以用于绑定对象,返回值加上"redirect:XXXX"就可以重定向 方法级别数据绑定@ModelAttribute注释一个方法的参数
1.从Model中获取
2.从Form表单或URL参数中获取(实际上,不做此注释也能拿到user对象)
redirect(重定向)/forward(请求转发)
@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(); }
4.4 fileUpload 单文件上传
①注册使用到的类:CommonsMultipartReslover类,这个类需要在spring的配置文件中进行配置,并设置一些必要的属性,比如是否延迟加载,上传文件的大小等等。 ②注意form表单中,对应的表单的name值应该和controller中参数Multipart file的名称一致,另外注意表单提交方式为post,MIME编码为multipart/form-data ③在controller中通过传入的参数类型为Multipart file并且使用@Requestparam注解,完成参数的绑定,这样表单中的file就被复制到参数对象中。然后通过Multipart的一些方法,
获取文件的名字信息并得到文件流对象,然后使用FileUtils类的copyInputStreamToFile(文件流,文件)完成文件的上传。
4.4.1 mvc-dispatcher-servlet.xml文件中加入如下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>
4.4.2 pom.xml文件里配置相关jar包依赖
4.4.3 Controller
@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"; }
4.5 JSON(一种轻量级的数据交换的格式)
springMVC使用viewResovler来处理含义相同格式不同(json xml html)的数据
4.5.1 mvc-dispatcher-servlet.xml文件中(记得加入依赖)
<!-- 配置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>
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); }
4.5.2 在前端使用ajax异步处理,触发请求,在请求的url中传入id,到后台之后,后台根据url,分解出pathVariable ,调用service方法,获得数据对象,然后返回@ResponseBody,此时,前台的ajax正在监听服务端的状态,如果是成功状态,将触发回调函数,函数中封装了对数据的逻辑,也就是使用js技术把数据对号入座,并且美化,展示页面。请求路径是一种restful风格。
前台异步获取数据
<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>
4.5.3 Json view的三种方式
ContentNegotiatingViewResolver 决定返回的数据是以Json还是jsp格式展示
ResponseEntity将返回的数据包裹在其中,便可以以Json格式返回
@ResponseBody/@ResquestBody 可以将请求值和返回值变成Json格式传输
5. summary