1.Spring MVC 概述

 

1.1 企业级应用基本架构

 

企业级应用中的软件的分层的基本架构(参考阿里巴巴开发手册)

spring项目打包指定字符集_MVC

说明:

分层架构的本质是分而治之,已达到分解问题复杂性的目的,从而更好的进行设计与实现。

1.2 Web MVC架构及分析

基于servlet,jsp,javabean技术实现的MVC架构,具体架构图如下:

spring项目打包指定字符集_xml_02

1.3 Spring MVC 架构及分析

Spring MVC是MVC架构模式的一种完美实现,它简化了Java WEB 中基于MVC架构的编程过程,是Spring中的WEB应用模块。

Spring MVC 底层核心架构图及工作流程(先了解,写完项目案例再重点强化)

spring项目打包指定字符集_spring项目打包指定字符集_03

Spring MVC 中的核心组件:

  • DispatcherServlet (前端控制器, 处理请求的入口)
  • HandlerMapping (映射器对象, 用于管理url与对应controller的映射关系)
  • Interceptors(拦截器,实现请求响应的共性处理)
  • Controller (后端控制器, 负责处理请求的控制逻辑)
  • ViewResolver(视图解析器,解析对应的视图关系:前缀+view+后缀)

备注:

假如希望了解Spring MVC的详细处理流程可以基于断点调试法进行跟踪。

2. Spring MVC 编程基础

2.1 Spring MVC 编程基本步骤

Step01:创建maven web 项目并解决项目中的错误问题

Step02:添加Spring MVC项目核心依赖

Step03:配置Spring MVC项目核心组件

Step04:创建Spring MVC 后端控制器及页面

Step05:部署及测试spring mvc 项目应用。

2.2 Spring MVC 编程基础实现(重点)

2.2.1 创建Maven WEB 项目并添加Spring MVC 依赖

Step01:创建maven web项目

  • 项目名 CGB-SPRING-MVC-01
  • Web项目打包方式为war方式

Step02:配置maven web项目

  • 生成web.xml(项目视图)

spring项目打包指定字符集_spring项目打包指定字符集_04

  • Web项目的target runtimes为tomcat

spring项目打包指定字符集_spring_05

  • Web 项目的编译版本为JDK1.8

spring项目打包指定字符集_xml_06

Step03: 添加Spring MVC项目依赖

<dependencies>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.3.9.RELEASE</version>
</dependency>
</dependencies>

2.2.2 添加Spring MVC配置文件并进行基本配置

在项目的resources的目录中添加核心配置文件(例如spring-configs.xml)并进行基本配置

<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true"
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:p="http://www.springframework.org/schema/p"
    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" 
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xsi:schemaLocation="  
       http://www.springframework.org/schema/beans   
       http://www.springframework.org/schema/beans/spring-beans-4.3.xsd  
       http://www.springframework.org/schema/mvc   
       http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd   
       http://www.springframework.org/schema/tx   
       http://www.springframework.org/schema/tx/spring-tx-4.3.xsd   
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
       http://www.springframework.org/schema/util 
       http://www.springframework.org/schema/util/spring-util-4.3.xsd
       http://www.springframework.org/schema/data/jpa 
       http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.3.xsd" >
  <!--配置组件扫描 -->
  <context:component-scan base-package="com.jt"/>
  <!—启用MVC默认配置 (@RequestMapping) -->
  <mvc:annotation-driven/>
  <!-- 配置视图解析器 -->
  <bean  id="viewResolver"   class="org.springframework.web.servlet.view.InternalResourceViewResolver">
       <property name="prefix" value="/WEB-INF/pages/"/>
       <property name="suffix" value=".jsp"/>
  </bean>
</beans>

说明:

配置文件的名字可以自己指定。

2.2.3 配置Spring MVC前端控制器

打开web.xml,配置DispatcherServlet对象

<servlet>
   <servlet-name>dispatcherServlet</servlet-name>
   <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class>
   <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-configs.xml</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
   <servlet-name>dispatcherServlet</servlet-name>
   <url-pattern>*.do</url-pattern>
</servlet-mapping>

前端控制器是spring mvc处理请求的入口,是springmvc的核心,这个控制器一般需要在服务器启动时即初始化。

其中

  • load-on-startup 表示启动时则加载此servlet,数字越小优先级越高.
  • init-param 中的参数名不能变(此名字在DispatcherServlet父类中定义)

2.2.4 创建并配置Spring MVC后端控制器

编写Spring MVC后端控制器

@Controller
@RequestMapping("/")
public class HelloController{
  @RequestMapping("doSayHello")
  public ModelAndView doSayHello() {
    ModelAndView mv=new ModelAndView("hello");
    mv.addObject("message", "helloworld");
    return mv;
  }
}

其中:

  • 通过@RequestMapping注解定义url到controller具体方法的映射,这个映射信息会被存储,一般是存储到一个HandlerMapping对象中.
  • ModelAndView对象为一个模型与视图对象,内置一个map对象,主要用于封装业务数据和视图名。
  • ModelAndView构造方法中传递的为视图名,addObject方法可以以key/value形式存储数据。
  • ModelAndView 对象返回时会被spring mvc自动存储到请求作用域,在对应的视图页面可以直接从此作用域获取对应的值。

2.2.5 创建JSP页面对象

在项目的WEB-INF/pages文件夹下创建hello.jsp文件,然后设置其内容,例如

<body>
   <h1>${message}</h1>
</body>

说明:

WEB-INF目录下的资源不能允许通过浏览器地址栏直接访问。

2.2.6 部署并运行项目以及请求响应流程分析

将项目部署到tomcat,然后启动运行,在地址栏输入具体url访问对应controller对象。

问题分析:

1)tomcat启动时出现ClassNotFoundException,而这个class又不是我们自己的类,此时要重新maven update,重新发布(右键tomcat 重新publish),多次尝试还是不可以,此时重启eclipse。

2)404异常,一般表示服务端资源没找到,首先检测访问路径是否正确,然后还可以在项目的部署目录中去查找对应的资源,必须确保资源是存在的,假如资源不存在,说明代码没有正常编译。(很常见)

3)如何解决这种项目不编译的问题?

  1. 停止tomcat将tomcat下的项目移除,并clean你的tomcat服务器(两个clean)
  2. 对项目进行maven clean操作(清除原先编译结构,然后重新编译)
  3. 再次对项目进行clean操作(菜单栏中的project clean)
  4. 重新部署项目,启动tomcat运行
  5. 假如经历了以上几个步骤,还没解决此问题,重启eclipse再试

说明:

假如你的eclipse经常出现类似问题,换jdk。

4)运行项目时尽量不要右键运行选在run as /run on server

Tomcat 启动及对象加载流程分析:

spring项目打包指定字符集_spring项目打包指定字符集_07

项目的请求处理流程结构及过程解析:

spring项目打包指定字符集_spring_08

Step01:客户端向服务服务端发请求

Step02:服务端对请求信息进行过滤(Filter)

Step03:请求到达前端控制DispatcherServlet

Step04:前端控制器基于url在HandlerMapping中的映射找请求执行链

Step05:执行执行链中的拦截器(Interceptor)方法

Step06:执行执行链中的控制器(Controller)方法

Step07:对象控制层返回的视图进行解析

Step08:向客户端返回一个响应结果。

3. Spring MVC 请求处理

3.1 请求路径映射

实际项目中我们要借助@RequestMapping注解定义映射路径。其注解应用位置

  • 类定义处: 提供初步的请求映射信息。
  • 方法定义处: 提供进一步的细分映射信息

3.1.1 普通url映射

@RequestMapping(value={"/doSayHello", "/user/doSayWelcome"}):

多个URL路径可以映射到同一个处理器的功能处理方法。

3.1.2 Rest风格url映射

REST即表述性状态传递(英文:Representational State Transfer,简称REST),是一种软件架构编码风格,是基于网络应用进行设计和开发的编码方式。可以降低开发的复杂度,提高程序的可伸缩性。

例如:

@RequestMapping("/msg/{xxx}") 

请求的URL可以是“/msg/hello”或“/msg/welcome”

 

@RequestMapping("/msg/{id}/create"):

请求的URL可以是“/users/1/create”。

 

@RequestMapping("/msg/{mId}/topics/{tId}")

这样也是可以的,请求的URL可以是“/users/10/topics/12”。

 

说明:

通过@PathVariable可以提取URI模板模式中的{×××}中的×××变量。

http://localhost:8080/项目名/doUpdate/1.do

3.2 请求方式映射

3.2.1 请求方式限定

项目中Controller层对象的每个方法默认可以处理任意方式的请求,假如要指定控制层方法只能处理GET或只能处理POST请求,那该如何实现呢?

借助@RequestMapping注解中的method属性指定具体的请求处理方式

例如:

@RequestMapping(value=”doSaveObj”,
method=RequestMethod.POST)
public String doSaveObject(Object obj){….}

知识点扩展:

1)@GetMapping 注解应用(定义的映射只能处理get请求)

2)@PostMapping 注解应用(定义的映射只能处理post请求)

3.2.2 请求方式组合

项目中还可在控制层方法上借助@RequestMapping注解中的method属性指定使用哪几种方式处理请求。

@RequestMapping(value=”doSaveObj”,method={RequestMethod.POST,RequestMethod.GET})
public String doSaveObject(Object obj){….}

 提示:一般浏览器只支持GET或POST方式。

3.3 请求参数映射(重点)

3.3.1 标准Servlet API(了解)

请求映射方法中可以直接使用ServletAPI 中的对象获取参数数据,例如

HttpServletRequest,HttpSession对象等

例如:

@RequestMapping(value="withRequest",method=RequestMethod.GET)
@ResponseBody
public String withRequest(HttpServletRequest request){
    System.out.println(request.getRequestURI());
    return "Obtainer 'foo' query parameter value '"+request.getParameter("gid")+"'";
}

提示:

@ResponseBody注解作用:

该注解作用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区

使用情况:

返回的数据不是Html标签的页面,而是其他数据格式的数据时,(如Json、xml,普通文本等)使用;

3.3.2 直接量对象(重点)

SpringMVC 请求一个控制层资源时,可以在对应方法中直接使用参数变量接收参数数据,但参数变量的类型建议为对象类型。

使用String类型变量接受请求参数的值:

@RequestMapping(value="withStringParam",method=RequestMethod.GET)
@ResponseBody
public String withStringParam(@RequestParam String foo) {
  return "Obtained 'foo' query parameter value '" + foo + "'";
}

提示:

@RequestParam注解用于接收请求参数中名字为foo的参数值

假如请求参数名与方法中的参数名一致,@RequestParam注解可以省略;

假如不一致则可以使用@RequestParam注解定义新的参数名直接接收页面数据,然后传递给方法名

还有就是请求参数中包含特殊字符时,需要借助@RequestParam注解对参数进行声明

例如:

@RequestMapping(value="withStringParam", method=RequestMethod.GET)
@ResponseBody
public String withStringParam(
@RequestParam(value="param-01",required=false) String foo) {
    return "Obtained 'foo' query parameter value '" + foo + "'";
}

提示:

required=false表示,参数可以不存在,假如为true(默认),参数不存在时会抛出异常(400异常)。

使用Date类型变量接受请求日期参数的值:

@RequestMapping(value="withDateParam")
@ResponseBody
public String withDateParam(Date birthday) {
  return "Obtained date parameter value '" + birthday + "'";
}

Spring MVC 默认支持yyyy/MM/dd格式日期转换,假如日期格式不匹配会报400异常

使用Integer类型的可变参数或数组接收请求数据

@RequestMapping(value="withVarParam")
@ResponseBody
public String withVarParam(Integer… ids) {
  return "Obtained ids parameter value '" + ids + "'";
}

3.3.3 Java bean对象(重点)

当请求中多个参数时可以通过在方法中定义多个参数接收参数数据,也可以利用一个javabean对象接收多个参数数据以简化多个参数变量的定义。

@RequestMapping(value="withParamGroup",method=RequestMethod.GET)
@ResponseBody
public String withParamGroup(SysLog entity) {
    return "Obtained javabean parameter group " + entity;
}

提示:

当使用javabean接收请求参数数据时,bean中需要有与参数名对应的set方法。

3.3.4 集合Map对象对象(了解)

说明:

通过map接收页面参数时,需要使用@RequestParam注解声明

@RequestMapping("doMap02")
public String withParamGroup (
@RequestParam Map<String,Object> map) {
	return "Obtained map parameter group " + map;
}

提示:

此时的map不能再作为响应数据的封装对象

3.3.5 Rest url数据(重点)

SpringMVC请求资源路径的URL可以通过{XXX}形式指定动态的URL,动态URL中的这个可变参数的值可以直接注入到方法对应的参数中。

@RequestMapping(value="path/{var}",method=RequestMethod.GET)
@ResponseBody
public String withPathVariable(@PathVariable String var) {
    return "Obtained 'var' path variable value '" + var + "'";
}

通过@PathVariable注解指定参数变量var获取请求url中{var}数据

3.3.6 请求头数据(了解)

当服务端要获取客户端请求头中数据信息时,可通过@RequestHeader即可将请求头中

的属性值绑定到处理方法的入参中,例如获取请求中Accept属性的值,然后传入到对应方法的参数中。

@RequestMapping(value="header", method=RequestMethod.GET)
@ResponseBody
public String withHeader(@RequestHeader String Accept) {
    return "Obtained 'Accept' header '" + Accept + "'";
}

假如希望在此方法中直接从cookie取值,可以定义参数时使用@CookieValue对参数进行修饰,参数名一般要与cookie对象中的key相同

@RequestMapping(value="withCookie")
@ResponseBody
public String withCooke(
@CookieValue String JSESSIONID) {
    return "Obtained COOKIE Value '" + JSESSIONID + "'";
}

提示:

方法中的参数名需要与请求头参数中某个参数名相同,具体请求头相关信息可以在浏览器控制台查看。

当应用中要获取请求中所有数据时可以在请求方法中定义一个HttpEntity<String>参数,通过此参数获取请求头及请求体中数据

例如:

@RequestMapping(value="entity", method=RequestMethod.POST)
public @ResponseBody String withEntity(
HttpEntity<String> entity) {
    return "Posted request body " + entity.getBody() + " headers = " + entity.getHeaders();
}

如上写法:了解

4. Spring MVC 响应处理

4.1 响应数据封装

4.1.1 Servlet API 对象(了解)

将请求数据直接封装到Request 对象

@RequestMapping("doResponse01")
public String doResponse01(HttpServletRequest request) {
  request.setAttribute("data", "hello..");
  return "response";
}

在response.jsp页面可以直接借助${data}方式获取数据。

当方法中直接返回一个页面时,默认执行的是请求转发,假如需要实现重定向,

可以在返回的地址后添加redirect

例如: 

return "redirect:responseUI.do"; 其中responseUI.do对应一个请求url.

@RequestMapping("doResponse02")
public String doResponse02(HttpServletRequest request) {
  request.setAttribute("data", "hello..");
  return "redirect:responseUI.do";
}

在如上方法中可以重定向到一个responseUI对应的新的URL。

@RequestMapping("responseUI")
public String responseUI() {
    return "response";
}

在新的请求中不能直接获取上一个请求作用域的数据。

 

回顾请求转发与重定向:

1)请求转发(forward)

spring项目打包指定字符集_java_09

2)重定向(redirect)

spring项目打包指定字符集_java_10

4.1.2 ModelAndView 对象(重点)

在对服务端响应数据进行封装时,可以直接在方法参数中定义一个ModelAndView类型的参数,借助ModelAndView对象封装响应数据.

@RequestMapping("doModelAndView")
public ModelAndView doModelAndView(ModelAndView mv) {
    //ModelAndView mv=new ModelAndView();
    mv.addObject("data", "model and view");
    mv.setViewName("response");//view
    return mv;
}

提示:

ModelAndView 对象由Spring创建,并可以将数据存储到ModelAndView对象的ModalMap类型的属性中(可参考源代码).

4.1.3 Model对象(重点)

将响应数据直接封装为model中。

@RequestMapping("doModel")
public String doModel(Model model) {
    model.addAttribute("data", "modal");
    return "response";
}

当我们返回具体view时,系统底层会自动将model对象存储到request作用域。

4.1.4 Map对象(了解)

将响应数据封装到Map中(我建议假如使用map对数据进行封装,可直接采用model对象)。

@RequestMapping("doMap01")
public String doMap01(Map<String,Object> map) {
  map.put("data", "map..");
  return "response";
}

4.2 响应数据转换JSON(重点)

4.2.1 JSON 应用概述

JSON(JavaScript Object Notation):一种轻量级数据交换格式,通常作为客户端与服务端进行数据交互的一种标准。

企业级Java项目数据传输方式:

spring项目打包指定字符集_spring_11

reponse.getWriter().write(jsonStr);

客户端访问服务端时,服务器从数据库取出数据进行封装,然后再将对象转换为json串,通过网络传输到客户端。

4.2.2 Spring 集成jackson库

spring 中默认支持jackson应用的,但使用时需要添加jackson依赖,例如

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.8.5</version>
</dependency>

创建Controller中例如ResponseController,然后在类中添加对应方法。例如

将Map对象内容转换为字符串(spring底层会直接访问jackson api将对象转换为字符串)

@RequestMapping("doMap")
@ResponseBody
public Map<String,Object> doMap(){
  Map<String,Object> map=
      new HashMap<>();
  map.put("id", 100);
  map.put("name", "AAA");
  return map;
}

将JavaBean对象转换为JSON串

@RequestMapping("doUser")
@ResponseBody
public SysLog doLog(){
  SysLog log=new SysLog ();
  log.setId(100);
  log.setUsername("CCC");
  log.setIP("192.168.1.12");
  return log;
}

将Java List集合转换为JSON串。

@RequestMapping("doList")
@ResponseBody
public List<SysLog> doList(){
  List<SysLog> list=new ArrayList<>();
  SysLog log=new SysLog ();
  log.setId(100);
  log.setUsername("CCC");
  log.setIP("192.168.1.12");
       list.add(log);
  log=new SysLog ();
  log.setId(100);
  log.setUsername("CCC");
  log.setIP("192.168.1.12");
  list.add(log);
  return list;
}

备注:将来controller中数据来自服务端数据。