Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的。


一、Spring MVC概述

在Spring的Web MVC框架提供了模型 - 视图 - 控制器架构以及可用于开发灵活,松散耦合的Web应用程序准备的组件。 MVC模式会导致分离的应用程序(输入逻辑,业务逻辑和UI逻辑)的不同方面,同时提供这些元素之间的松耦合。

优点:

  • SpringMVC通过一套MVC注释,让POJO成为处理请求的控制器,而无需实现任何接口。POJO就是普通的Java类 Plain old java Object。
  • 支持REST风格的URL请求
  • 采用了松散耦合可插拔组件结构,比其他MVC框架更具有扩展性和灵活性。

spring 实体JSON 字段排除 springmvc json解析_xml

1. 创建WEB工程

创建Dynamic Web Project -------> Target Runtime 要选Tomcat---- dynamic Web module version选2.5(3.0没有web.xml文件)

编写web.xml配置

需要在src路径下新建一个SpringMVC的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns="http://java.sun.com/xml/ns/javaee"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
     http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>SpringDispatcherServlet</display-name>
  <!-- 配置前端控制器DispatcherServlet -->
  <!--用来拦截所有的请求,前端控制器是一个Servlet求 -->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
    	<!--contextConfigLocation指定SpringMVC配置文件的位置 -->
        <param-name>contextConfigLocation</param-name>
        <!--classpath:springmvc.xml代表src(类路径)路径下的springmvc配置文件  -->
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!-- 服务器启动的时候创建对象,值越小优先级又高,越先创建对象 -->
    <load-on-startup>1</load-on-startup>
  </servlet>
 
  <servlet-mapping>
    <servlet-name>SpringDispatcherServlet</servlet-name>
    <!--拦截所有请求-->
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

编写springmvc.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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">
        
 		<!-- 扫描所有组件 -->
		<context:component-scan base-package="com.atguigu"></context:component-scan>
		<!-- 配置视图解析器,对return返回的值 进行拼接 -->
		<bean class="org.springframework.web.servlet.view.InternalResource">
 			<property name="prefix" value="/WEB-INF/pages/"></property>
			<property name="suffix" value=".jsp"></property>
		</bean>
</beans>

新建一个Controller

hello页面中有一个超链接,请求地址是/Hello,点击超链接之后,Controller中的会接受到请求,然后返回WEB-INF/pages/success.jsp页面,为啥会返回的是这个页面,因为在springMVC配置文件中进行配置了

@Controller
public class HelloController {
 
    @RequestMapping("/Hello")
    public String myFirstRequest() {
        System.out.println("请求收到了")
        //返回 /WEB-INF/pages/+success+后缀的页面
        ///WEB-INF/pages/success.jsp页面
        return "success";
    }
}

具体执行流程:

1. 客户端点击链接发送/Hello 请求
2. 来到Tomcat服务器
3. SpringMVC前端控制器收到所有的请求
4. 查看请求的地址与Controller中的@RequestMapping哪个匹配,从而找到到底使用哪个类中的方法
5. 前端控制器找到所在的类和方法后,执行目标方法
6. SpringMVC认为返回值就是要去的页面地址
7. 拿到返回值之后,用视图解析器进行拼接拿到完整的地址
8. 拿到页面地址后,前端视图器帮我们转发到页面

@RequestMapping

用来告诉SpringMVC当前方法用来处理什么请求

method属性:限定请求方式

method = RequestMethod.POST
method = RequestMethod.GET
默认是全接受

params属性

headers属性

如果在web.xml中不指定springmvc的配置文件的位置

会默认去/WEB-INF/XXX-servlet.xml,这个xxx就是在web.xml中配的前端控制器的名称,在这里我配置的前端控制器名称是SpringDispatcherServlet,因此这个文件是/WEB-INF/SpringDispatcherServlet-servlet.xml

因此,如果在web.xml中不指定springmvc的配置文件的位置,就在/WEB-INF/自己建一个与前端控制器名称一样的xml文件。

web.xml配置文件中的url- pattern

<servlet-mapping>
    <servlet-name>SpringDispatcherServlet</servlet-name>
    <!--拦截所有请求-->
    <url-pattern>/</url-pattern>
  </servlet-mapping>

/        是拦截所有请求,但是不拦截.jsp请求
/*         拦截所有请求包括jsp
*.jsp        是tomcat处理的事情

在web项目中,在服务器Servers的配置中也有一个web.xml的配置文件,我们的项目中WEB-INF下的web.xml实际上是继承自Servers下的web.xml的,可以看作是父类和子类的关系。
在服务器Servers下的web.xml中配置了一个DefaultServlet,url- pattern是/,这个DefaultServlet是Tomcat用来处理静态资源的(除了JSP和servlet外,剩下的都是静态资源)。在我们的配置文件中我们配置了一个SpringDispatcherServlet,url- pattern也是/,相当于子类重写父类了,也就是我们的SpringDispatcherServlet禁掉了DefaultServlet,因此这些请求便会交由DispatcherServler前端控制器这里。那为什么可以访问.jsp,因为在Servers下的web.xml中有一个jsp 的servlet,这个没有被我们覆盖,因此可以正常访问。当SpringDispatcherServlet配置成/* 会拦截所有的请求包括.jsp

ant风格的URL

?          @RequestMapping("/hello0?") 这个?相当于占位符。 模糊和精确多个匹配的情况下,精确优先
*          @RequestMapping("/hello0*") 0后面可以有任意多个字符 0或者多个。

@PathVariable注解

可以获取到路径上的占位符的值,

@RequestMapping("/hello0/{id}")
public String pathVariableTest(@PathVariable("id") String id){
	System.out.println("可以获取到路径上的占位符id"+id)
	return "success"
}

@RequestParam注解

获取请求参数两种方式:原生和使用注解

原生的方式

请求地址中的参数名称是什么,就将这个函数的形参写成什么。比如请求地址是/hello?username=allen

@RequestMapping("/hello")
public String handle02(String username){

	System.out.println("可以获取到请求参数"+username)
	return "success"
}

使用注解

@RequestParam(“username”)String username 这种方式只能获取到请求参数是username的值

@RequestMapping("/hello")
public String handle02(@RequestParam("username")String username){

	System.out.println("可以获取到请求参数"+username)
	return "success"
}

@RequestParam(“user”)String username这相当于将请求参数是user的值赋给了 username

@RequestMapping("/hello")
public String handle02(@RequestParam("user")String username){

	System.out.println("可以获取到请求参数"+username)
	return "success"
}

@RequestHeader注解h

获取到请求头中的参数

@RequestMapping("/hello")
public String handle02(@RequestHeader("User-Agent")String userAgent){

	System.out.println("获取到请求头"+userAgent)
	return "success"
}

@CookieValue注解h

@RequestMapping("/hello")
public String handle02(@CookieValue("JSESSIONID")String jid){

	System.out.println("获取到cookie"+userAgent)
	return "success"
}

如果我们的请求参数是一个POJO(也就是一个对象),Spring MVC会自动的为这个POJO对象进行赋值,怎么赋值呢?

1 首先将POJO中的每一个属性,从Request的参数中尝试获取,并封装即可
2 还可以级联封装

定义一个book类型对象

public class Book {
	private String bookName;
	private String author;
	private Double price;
}

提交表单到/hello

<form action="/hello" method="post">
	书名:<input type="text" name="bookName"/>
	作者:<input type="text" name="author"/>
	价格:<input type="text" name="price"/>
	<input type="submit">
</form>

接收到提交表单的请求,然后会将这些请求参数封装成book类型对象

@RequestMapping("/hello")
public String handle02(Book book){

	System.out.println("获取到Book对象"+book)
	return "success"
}

2 级联封装

定义一个Address类

public class Address {
	private String province;
	private String city;
}

定义一个book类

public class Book {
	private String bookName;
	private String author;
	private Double price;
	private Address address;
}

提交表单到/hello

<form action="/hello" method="post">
	书名:<input type="text" name="bookName"/>
	作者:<input type="text" name="author"/>
	价格:<input type="text" name="price"/>
	省:<input type="text" name="address.province"/>
	市:<input type="text" name="address.city"/>
	<input type="submit">
</form>

接收到提交表单的请求,然后会将这些请求参数封装成book类型对象

@RequestMapping("/hello")
public String handle02(Book book){

	System.out.println("获取到Book对象"+book)
	return "success"
}



乱码问题

1、接收到的请求乱码问题

Get请求,改server.xml文件配置

在8080端口处加上URIEncoding=“UTF-8”

POST请求

request.setCharacterEncoding("UTF-8")

或者在web.xml中配置一个字符编码的filter

<filter>
  	<filter-name>charsetEncodingFilter</filter-name>
  	<filter-class>com.aaa.filter.CharsetEncodingFilter</filter-class>
  	<!--解决POST请求乱码问题 -->
  	<init-param>
  		<param-name>encoding</param-name>
  		<param-value>UTF-8</param-value>
  	</init-param>
  	<!-- 顺手解决响应乱码,可以不要 -->
	<init-param>
  		<param-name>forceEncoding</param-name>
  		<param-value>true</param-value>
  	</init-param>
  </filter>
  
  <filter-mapping>
  	<filter-name>charsetEncodingFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

2注意,字符编码的filter一定要配置在其他filter之前,否则无法解决乱码问题

2、响应乱码问题

response.setContentType("text/html;charset=utf-8")

二、REST风格

用请求方式来表示对一个资源的增删改查的URL。

以前的形式
/getBook?id=1 查询1号图书
/deleteBook?id=1 删除1号图书
/updateBook?id=1 更新1号图书
/addBook 添加图书

REST推荐 用请求方式的不同进行区分
url地址 /资源名/资源标志符
/book/1 GET 查询1号图书
/book/1 PUT 更新1号图书
/book/1 DELETE删除1号图书
/book POST 添加图书

问题:页面中只能发起post和get请求,其他的请求方式无法使用


在web.xml配置支持Rest风格的filter

<filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
            <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
        </filter>
        
        <filter-mapping>
            <filter-name>HiddenHttpMethodFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
   </filter>



三、将请求的结果转发给页面

请求处理完成后,将请求的结果放在请求域中转发给页面。在SpringMVC中如何将数据带给页面

方式1 使用Model、ModelMap、Map,返回值为String。给这些类型的参数保存的数据都会传递到页面中,并在request域中获取到
方式2 使用ModelAndView,返回值也是ModelAndView

方式1

可以在request域中使用${requestScope.msg}获取到

传入Map

public String index(Map<String,Object> map){
	moMap.put("msg","你好" );
        return “success”
}

传入Model

public String index(Model model){
	model.addAttribute("msg", "你好");
    return “success”;
}

传入ModelMap

public String index(ModelMap modelMap){
	model.addAttribute("msg", "你好");
    return “success”;
}

方式2 ModelAndView

返回success.jsp页面

public ModelAndView login(){
  ModelAndView mv = new ModelAndView("success");
  mv.addObject("msg","你好哦" );
  return mv;
}

@SessionAttributes注解

前面的数据都是放在请求域Request域中的,事实上,SpringMVC也提供了一种可以临时给Session域中保存数据的方式,使用@SessionAttributes注解,该注解只可以标注在类上

使用@SessionAttributes(value=“msg”)的意思是:你在向Model、ModelMap、Map、ModelAndView添加键值为msg的数据的时候,也为session当中添加一份,结果就是session和request域中都有一份


使用@SessionAttributes(value=“msg”,type={String.class})的意思是:你在向Model、ModelMap、Map、ModelAndView添加的数据只要是String类型的,不管键值是不是msg,我都向session中保存一份

四、SpringMVC执行过程

(1)所有的请求过来,DispatcherServlet收到请求
(2)调用do Dispatch( )进行处理

(1) getHandler( ):根据当前请求地址找到能够处理这个请求的目标处理器handler(处理器类Controller)
(2)getHandlerAdapter( ):根据当前处理器类找到能够执行这个处理器方法的适配器
(3)使用刚才获取到的适配器(AnnotationMethodHandlerAdpater)执行目标方法
(4)目标方法执行后会返回一个ModelAndView对象
(5)根据ModelAndView的信息转发到具体的页面,并可以在请求域中获取出ModelAndView

(3)getHandler方法如何实现的呢或者说如何找到handler的呢?就是通过HandlerMapping这样一个处理器映射器,获取到目标处理类

(4)如何拿到适配器?遍历所有的handlerAdapters,有三种类型的适配器,对我们有用的是AnnotationMethodHandlerAdpater类型的适配器对我们有用

五、视图解析器

页面转发 forward:

表示转发到当前项目目录下的hello.jsp,这中就不会在添加前缀了

return "forward:/hello.jsp";

重定向 redirect:

return "redirect:/hello.jsp";

jstl View 国际化功能
在我们的视图解析器成我们配置的是InternalResource解析器

<bean class="org.springframework.web.servlet.view.InternalResource">
 			<property name="prefix" value="/WEB-INF/pages/"></property>
			<property name="suffix" value=".jsp"></property>
			
</bean>

当我们导入包之后

在创建的时候,会自动将视图创建成为JstlView,而不是Internal ResourceView Resolver,可以快速使用国际化功能。

如果不导包,但是想创建JstlView解析器,可以指定property

<bean class="org.springframework.web.servlet.view.InternalResource">
 			<property name="prefix" value="/WEB-INF/pages/"></property>
			<property name="suffix" value=".jsp"></property>
			<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
			
</bean>

JavaWeb国际化操作步骤:

有了JstlView之后,操作国际化之需要:

让Spring管理国际化资源就可以
然后直接去页面使用

在Springmvc配置文件中进行配置,这个id的名字必须为messageSource

<bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource">
        <!--指定国际化文件的基础名-->
        <property name="basename" value="i180"> </property>
</bean>

配置好之后,直接去页面中使用< fmt:message> 标签进行使用

注意,在发送转发请求的时候,会为我们创建一个Internal ResourceView视图解析器,因此,可能会造成国际化资源失效的问题。因此不能够带forward前缀使用jstl的国际化功能,只能采用拼接的形式

//这种形式 会使jstl的国际化功能失效
return "forward:/WEB/INF/pages/login.jsp"
//将上述形式改为拼接   可以正常使用jstl的国际化
return "login.jsp"

mvc:view- controller

发送一个请求,仅仅是为了来到一个页面,其余什么操作也没做,针对于这样的操作我们就需要写一个方法。那么在一个系统的设计过程中,可能有很多这样的需求,然后就需要写很多这样的方法。针对于上述这种问题,可以在springmvc配置文件中使用mvc:view-controller标签进行解决。

<!-- 发送一个请求/toLoginPage,view-name指定映射给哪个视图,相当于return success,这里的login就是success,自己进行前后缀拼接 -->
<mvc:view-controller path="/toLoginPage" view-name="login">

如果不想进行拼接的话可以,可以使用下面的方式,会去项目目录下找login.jsp

<mvc:view-controller path="/toLoginPage" view-name="forward:/login.jsp">

注意,但是这个只针对于当前的/toLoginPage请求有效,那对于其他请求login.jsp的页面就失效了,这怎么办?开启注解驱动的MVC模式

注解驱动的MVC模式

<mvc:annotation-driven></mvc:annotation-driven>

因此完整配置是:

<mvc:view-controller path="/toLoginPage" view-name="login">
<mvc:annotation-driven></mvc:annotation-driven>

视图解析器根据方法的返回值创建视图对象