1、SpringMVC 框架详细介绍
Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的。
与之相反的是基于组件的、事件驱动的Web框架,如Tapestry、JSF等,在此就不介绍了。
Spring Web MVC也是服务到工作者模式的实现,但进行可优化。前端控制器是DispatcherServlet;应用控制器其实拆为处理器映射器(Handler Mapping)进行处理器管理和视图解析器(View Resolver)进行视图管理;页面控制器/动作/处理器为Controller接口(仅包含ModelAndView handleRequest(request, response) 方法)的实现(也可以是任何的POJO类);支持本地化(Locale)解析、主题(Theme)解析及文件上传等;提供了非常灵活的数据验证、格式化和数据绑定机制;提供了强大的约定大于配置(惯例优先原则)的契约式编程支持。
2、SpringMVC 处理请求流程
第一步:用户发送请求到前端控制器(DispatcherServlet)。
第二步:前端控制器请求 HandlerMapping 查找 Handler,可以根据 xml 配置、注解进行查找。
第三步: 处理器映射器 HandlerMapping 向前端控制器返回 Handler
第四步:前端控制器调用处理器适配器去执行 Handler
第五步:处理器适配器执行 Handler
第六步:Handler 执行完成后给适配器返回 ModelAndView
第七步:处理器适配器向前端控制器返回 ModelAndView
ModelAndView 是SpringMVC 框架的一个底层对象,包括 Model 和 View
第八步:前端控制器请求试图解析器去进行视图解析
根据逻辑视图名来解析真正的视图。
第九步:试图解析器向前端控制器返回 view
第十步:前端控制器进行视图渲染
就是将模型数据(在 ModelAndView 对象中)填充到 request 域
第十一步:前端控制器向用户响应结果
下面我们对上面出现的一些组件进行解释:
1、前端控制器DispatcherServlet(不需要程序员开发)。
作用:接收请求,响应结果,相当于转发器,中央处理器。有了DispatcherServlet减少了其它组件之间的耦合度。
2、处理器映射器HandlerMapping(不需要程序员开发)。
作用:根据请求的url查找Handler。
3、处理器适配器HandlerAdapter(不需要程序员开发)。
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler。
4、处理器Handler(需要程序员开发)。
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
5、视图解析器ViewResolver(不需要程序员开发)。
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
6、视图View(需要程序员开发jsp)。
注意:View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
ps:不需要程序员开发的,需要程序员自己做一下配置即可。
|
可以总结出:需要我们开发的工作只有处理器 Handler 的编写以及视图比如JSP页面的编写。可能你还对诸如前端控制器、处理器映射器等等名词不太理解,那么接下来我们对其进行详细的介绍。
3、配置前端控制器
在 web.xml 文件中进行如下配置:
<? xml versinotallow="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:schemaLocatinotallow="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" versinotallow="3.0">
< display-name >SpringMVC_01</ display-name >
<!-- 配置前端控制器DispatcherServlet -->
< servlet >
< servlet-name >springmvc</ servlet-name >
< servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class >
<!--springmvc.xml 是自己创建的SpringMVC全局配置文件,用contextConfigLocation作为参数名来加载
如果不配置 contextConfigLocation,那么默认加载的是/WEB-INF/servlet名称-servlet.xml,在这里也就是 springmvc-servlet.xml
-->
< init-param >
< param-name >contextConfigLocation</ param-name >
< param-value >classpath:springmvc.xml</ param-value >
</ init-param >
</ servlet >
< servlet-mapping >
< servlet-name >springmvc</ servlet-name >
<!--第一种配置:*.do,还可以写*.action等等,表示以.do结尾的或者以.action结尾的URL都由前端控制器DispatcherServlet来解析
第二种配置:/,所有访问的 URL 都由DispatcherServlet来解析,但是这里最好配置静态文件不由DispatcherServlet来解析
错误配置:/*,注意这里是不能这样配置的,应为如果这样写,最后转发到 jsp 页面的时候,仍然会由DispatcherServlet进行解析,
而这时候会找不到对应的Handler,从而报错!!!
-->
< url-pattern >*.do</ url-pattern >
</ servlet-mapping >
</ web-app >
|
4、配置处理器适配器
在 springmvc.xml 文件中配置。用来约束我们所需要编码的 Handler类。
第一种配置:编写 Handler 时必须要实现 Controller
<!-- 配置处理器适配器,所有适配器都得实现 HandlerAdapter接口 -->
< bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
|
我们可以查看源码:
第二种配置:编写 Handler 时必须要实现 HttpRequestHandler
1 2 |
<!-- 配置处理器适配器第二种方法,所有适配器都得实现 HandlerAdapter接口 ,这样配置所有Handler都得实现 HttpRequestHandler接口-->
< bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />
|
5、编写 Handler
在 springmvc.xml 文件中配置。通俗来讲,就是请求的 URL 到我们这里所编写的 Handler 类的某个方法进行一些业务逻辑处理。
我们在上面讲解了两个处理器适配器来约束 Handler,那么我们就通过上面两种配置分别编写两个 Handler
第一种:实现Controller 接口
package com.ys.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class HelloController implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
ModelAndView modelView = new ModelAndView();
//类似于 request.setAttribute()
modelView.addObject("name","张三");
modelView.setViewName("/WEB-INF/view/index.jsp");
return modelView;
}
}
|
第二种:实现 HttpRequestHandler 接口
package com.ys.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.HttpRequestHandler;
public class HelloController2 implements HttpRequestHandler{
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("name", "张三");
request.getRequestDispatcher("/WEB-INF/view/index.jsp").forward(request, response);
}
}
|
总结:通常我们使用第一种方式来编写 Handler ,但是第二种没有返回值,我们可以通过 response 修改相应内容,比如返回 json 数据。
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json字符串");
|
所以具体使用哪一种根据实际情况来判断。
5、配置处理器映射器
在 springmvc.xml 文件中配置。通俗来讲就是请求的 URL 怎么能被 SpringMVC 识别,从而去执行我们上一步所编写好的 Handler
第一种方法:
<!-- 配置Handler -->
< bean name="/hello.do" class="com.ys.controller.HelloController2" />
<!-- 配置处理器映射器
将bean的name作为url进行查找,需要在配置Handler时指定bean name(就是url)-->
< bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
|
这样配置的话,那么请求的 URL,必须为 http://localhost:8080/项目名/hello.do
第二种方法:
<!-- 配置Handler -->
< bean id="hello1" class="com.ys.controller.HelloController" />
< bean id="hello2" class="com.ys.controller.HelloController" />
<!-- 第二种方法:简单URL配置处理器映射器 -->
< bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
< property name="mappings">
< props >
< prop key="/hello1.do">hello1</ prop >
< prop key="/hello2.do">hello2</ prop >
</ props >
</ property >
</ bean >
|
这种配置请求的 URL可以为 http://localhost:8080/项目名/hello1.do,或者http://localhost:8080/项目名/hello2.do
总结:上面两种处理器映射器配置可以并存,前端控制器会正确的去判断 url 用哪个 Handler 去处理。
6、配置视图解析器
第一种配置:
<!-- 配置视图解析器
进行jsp解析,默认使用jstl标签,classpath下得有jstl的包-->
< bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
|
如果这样配,那么在 Handler 中返回的必须是路径+jsp页面名称+".jsp"
第二种配置:
<!--配置视图解析器 -->
< bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 返回视图页面的前缀 -->
< property name="prefix" value="/WEB-INF/view"></ property >
<!-- 返回页面的后缀 -->
< property name="suffix" value=".jsp"></ property >
</ bean >
|
如果这样配,那么在 Handler 中只需要返回在 view 文件夹下的jsp 页面名就可以了。
7、DispatcherServlet.properties
上面我们讲解了各种配置,可能有人会问这么多配置,万一少配置了一样,那不就不能运行了,那我们能不能不配置呢?答案是肯定的,SpringMVC 给我们提供了一个 DispatcherServlet.properties 文件。系统会首先加载这里面的配置,如果我们没有配置,那么就默认使用这个文件的配置;如果我们配置了,那么就优先使用我们手动配置的。
在 SpringMVC 运行之前,会首先加载 DispatcherServlet.properties 文件里面的内容,那么我们来看看这里面都是什么。
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.HandlerExceptinotallow=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
|
我们可以从上面得出,如果我们不手动进行各种配置,那么也有会默认的
①、处理器适配器默认:org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
②、处理器映射器默认:org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
③、视图解析器默认:org.springframework.web.servlet.view.InternalResourceViewResolver
前两篇博客我们讲解了基于XML 的入门实例,以及SpringMVC运行的详细流程。但是我们发现基于 XML 的配置还是比较麻烦的,而且,每个 Handler 类只能有一个方法,在实际开发中肯定是不可能这样来进行开发的。那么这篇博客我们就讲解实际开发中用的最多的基于注解配置的SpringMVC配置。
项目结构为:
1、在 web.xml 文件中配置前端处理器#
<? xml versinotallow="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:schemaLocatinotallow="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" versinotallow="3.0">
< display-name >SpringMVC_01</ display-name >
<!-- 配置前端控制器DispatcherServlet -->
< servlet >
< servlet-name >springmvc</ servlet-name >
< servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class >
<!--springmvc.xml 是自己创建的SpringMVC全局配置文件,用contextConfigLocation作为参数名来加载
如果不配置 contextConfigLocation,那么默认加载的是/WEB-INF/servlet名称-servlet.xml,在这里也就是 springmvc-servlet.xml
-->
< init-param >
< param-name >contextConfigLocation</ param-name >
< param-value >classpath:springmvc.xml</ param-value >
</ init-param >
</ servlet >
< servlet-mapping >
< servlet-name >springmvc</ servlet-name >
<!--第一种配置:*.do,还可以写*.action等等,表示以.do结尾的或者以.action结尾的URL都由前端控制器DispatcherServlet来解析
第二种配置:/,所有访问的 URL 都由DispatcherServlet来解析,但是这里最好配置静态文件不由DispatcherServlet来解析
错误配置:/*,注意这里是不能这样配置的,应为如果这样写,最后转发到 jsp 页面的时候,仍然会由DispatcherServlet进行解析,
而这时候会找不到对应的Handler,从而报错!!!
-->
< url-pattern >/</ url-pattern >
</ servlet-mapping >
</ web-app >
|
2、在 springmvc.xml 文件中配置处理器映射器,处理器适配器,视图解析器
<? xml versinotallow="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:cnotallow="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocatinotallow="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">
<!--注解处理器映射器 -->
< bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></ bean >
<!--注解处理器适配器 -->
< bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></ bean >
<!--使用mvc:annotation-driven可以代替上面的映射器和适配器
这里面会默认加载很多参数绑定方法,比如json转换解析器就默认加载,所以优先使用下面的配置
-->
<!-- <mvc:annotation-driven></mvc:annotation-driven> -->
<!--单个配置Handler -->
<!-- <bean class="com.ys.controller.HelloController"></bean> -->
<!--批量配置Handler,指定扫描的包全称 -->
< context:component-scan base-package="com.ys.controller"></ context:component-scan >
<!--配置视图解析器 -->
< bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 返回视图页面的前缀 -->
< property name="prefix" value="/WEB-INF/view/"></ property >
<!-- 返回页面的后缀 -->
< property name="suffix" value=".jsp"></ property >
</ bean >
</ beans >
|
3、编写 Handler
package com.ys.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
//使用@Controller注解表示这个类是一个Handler
@Controller
public class HelloController {
//@RequestMapping注解括号里面的表示访问的URL
@RequestMapping("hello")
public ModelAndView hello(){
ModelAndView modelView = new ModelAndView();
//类似于 request.setAttribute()
modelView.addObject("name","张三");
//配置返回的视图名,由于我们在springmvc.xml中配置了前缀和后缀,这里直接写视图名就好
modelView.setViewName("index");
//modelView.setViewName("/WEB-INF/view/index.jsp");
return modelView;
}
}
|
注意@Controller注解和@RequestMapping注解的用法
4、编写 视图 index.jsp
<%@ page language="java" cnotallow="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" cnotallow="text/html; charset=UTF-8">
< title >Insert title here</ title >
</ head >
< body >
hello:${name}
</ body >
</ html >
|
5、在浏览器中输入:http://localhost:8080/SpringMVC_03/hello
为了后面讲解的需要,我们取数据都会从数据库中获取,所以这里先讲讲三大框架(Spring、SpringMVC、MyBatis)的整合。前面讲解 MyBatis 时,写了一篇 MyBatis 和 Spring 的整合,
1、整合思路
①、表现层,也就是 Controller,由 SpringMVC 来控制,而SpringMVC 是Spring 的一个模块,故不需要整合。
②、业务层,也就是 service,通常由 Spring 来管理 service 接口,我们会使用 xml 配置的方式来将 service 接口配置到 spring 配置文件中。而且事务控制一般也是在 service 层进行配置。
③、持久层,也就是 dao 层,而且包括实体类,由 MyBatis 来管理,通过 spring 来管理 mapper 接口,使用mapper的扫描器自动扫描mapper接口在spring中进行注册。
很明显,spring 在三大框架的整合中占据至关重要的地位,类似于一个大管家,将 MyBatis 和 SpringMVC 揉合在一起。
2、准备环境
①、数据库环境
数据库类型:MySQL 5.1
数据库名称:ssm
数据表:user
②、开发工具 eclipse
③、JDK 1.7
④、mybatis 3.3
⑤、SpringMVC 4.2.4
⑥、Spring 4.2.4
⑦、数据库连接池 dbcp1.2.2
⑧、数据库驱动包mysql5.1.26
⑨、日志 log4j 1.2
案例需求:输入用户名和密码进行登录验证
具体的 jar 下载见上面的源码下载链接!
项目的目录结构为:
3、整合 Dao 层
也就是整合 MyBatis 和 Spring
①、在 db.properties 文件中,保存数据库连接的基本信息
#db.properties
dataSource=org.apache.commons.dbcp.BasicDataSource
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/ssm
username=root
password=root
|
分别是数据库连接池数据源,数据库连接驱动,数据库连接URL,数据库连接用户名,数据库连接密码
②、mybatis全局配置文件 mybatis-configuration.xml
<? xml versinotallow="1.0" encoding="UTF-8"?>
<! DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
< configuration >
<!-- 全局 setting 配置,根据需要添加 -->
<!--开启二级缓存 -->
< settings >
< setting name="cacheEnabled" value="true"/>
</ settings >
<!-- 配置别名 -->
< typeAliases >
<!-- 批量扫描别名 -->
< package name="com.ys.po"/>
</ typeAliases >
<!-- 配置mapper,由于使用 spring 和mybatis 的整合包进行 mapper 扫描,这里不需要配置了
必须遵循:mapper.xml 和 mapper.java 文件同名且在同一个目录下
-->
<!-- <mappers>
</mappers> -->
</ configuration >
|
通过 mapper 接口来加载映射文件,必须满足下面四点:
1、xxxMapper 接口必须要和 xxxMapper.xml 文件同名且在同一个包下,也就是说 UserMapper.xml 文件中的namespace是UserMapper接口的全类名
2、xxxMapper接口中的方法名和 xxxMapper.xml 文件中定义的 id 一致
3、xxxMapper接口输入参数类型要和 xxxMapper.xml 中定义的 parameterType 一致
4、xxxMapper接口返回数据类型要和 xxxMapper.xml 中定义的 resultType 一致
③、配置 Spring 文件
我们需要配置数据源、SqlSessionFactory以及mapper扫描器,由于这是对 Dao 层的整合,后面还有对于 业务层,表现层等的整合,为了使条目更加清新,我们新建 config/spring 文件夹,这里将配置文件取名为 spring-dao.xml 放入其中。
spring-dao.xml
<? xml versinotallow="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:cnotallow="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocatinotallow="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!--第一步: 配置数据源 -->
<!-- 加载db.properties文件中的内容,db.properties文件中的key名要有一定的特殊性 -->
< context:property-placeholder locatinotallow="classpath:db.properties" />
< bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
< property name="driverClassName" value="${jdbc.driver}"></ property >
< property name="url" value="${jdbc.url}"></ property >
< property name="username" value="${jdbc.username}"></ property >
< property name="password" value="${jdbc.password}"></ property >
< property name="maxActive" value="30"></ property >
< property name="maxIdle" value="5"></ property >
</ bean >
<!-- 第二步:创建sqlSessionFactory。生产sqlSession -->
< bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据库连接池 -->
< property name="dataSource" ref="dataSource"></ property >
<!-- 加载mybatis全局配置文件,注意这个文件的目录 -->
< property name="configLocation" value="classpath:mybatis/mybatis-configuration.xml"></ property >
</ bean >
<!-- 第三步:配置 mapper 扫描器
* 接口类名和映射文件必须同名
* 接口类和映射文件必须在同一个目录下
* 映射文件namespace名字必须是接口的全类路径名
* 接口的方法名必须和映射Statement的id一致
-->
< bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 扫描的包路径,如果需要扫描多个包,中间使用逗号分隔 -->
< property name="basePackage" value="com.ys.mapper"></ property >
< property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></ property >
</ bean >
</ beans >
|
④、根据逆向工程生成 po 类以及 mapper 文件
如何使用逆向工程,我们逆向工程要是一个额外的工程,生成我们所需的po类以及mapper文件后,在将其复制到我们当前项目中,如下:
由于我们这里是进行登录验证,所以在 UserMapper.java 中添加如下代码:
package com.ys.mapper;
import com.ys.po.User;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface UserMapper {
//通过用户名和密码查询User
User selectUserByUsernameAndPassword(User user);
}
|
UserMapper.xml
<!-- 通过用户名和密码查询User -->
<select id= "selectUserByUsernameAndPassword" resultType= "com.ys.po.User" parameterType= "com.ys.po.User" >
select * from user where username = #{username,jdbcType=VARCHAR} and password = #{password,jdbcType=VARCHAR}
</select>
|
dao 层整合完毕之后,我们进行一个测试,要养成每做完一个小模块必须测试的习惯。步步为营,如果整个项目配置完了然后在进行测试,那么有问题进行排除会变得很困难。
package com.ys.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ys.mapper.UserMapper;
import com.ys.po.User;
public class DaoTest {
ApplicationContext context = null ;
@Before
public void init(){
context = new ClassPathXmlApplicationContext( "classpath:spring/application-dao.xml" );
}
@Test
public void testSelectByPrimaryKey(){
UserMapper userMapper = (UserMapper) context.getBean( "userMapper" );
User user = userMapper.selectByPrimaryKey( 1 );
System.out.println(user.getPassword());
}
}
|
这里是根据 user 表的 id 进行查询。如果能打印出user对象的值,那么前面的配置是 OK的。
4、整合 service
前面我们整理了,这层就是用 Spring 来管理 service 接口,我们会使用 xml 配置的方式来将 service 接口配置到 spring 配置文件中。而且事务控制也是在 service 层进行配置。
这里我们以登录
①、定义 service 接口
package com.ys.service.impl;
import com.ys.po.User;
public interface IUserService {
//通过用户名和密码查询User
public User selectUserByUsernameAndPassword(User user);
}
|
②、编写 service 实现类
package com.ys.service;
import org.springframework.beans.factory.annotation.Autowired;
import com.ys.mapper.UserMapper;
import com.ys.po.User;
import com.ys.service.impl.IUserService;
public class UserServiceImpl implements IUserService{
@Autowired
private UserMapper userMapper; //通过@Autowired向spring容器注入UserMapper
//通过用户名和密码查询User
@Override
public User selectUserByUsernameAndPassword(User user) {
User u = userMapper.selectUserByUsernameAndPassword(user);
return u;
}
}
|
通过@Autowired向spring容器注入UserMapper,它会通过spring配的扫描器扫描到,并将对象装载到spring容器中。
③、在spring容器中配置 Service 接口,这里我们使用 xml 的方式
在 config/spring 目录下,新建 spring-service.xml
<?xml versinotallow= "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:cnotallow= "http://www.springframework.org/schema/context"
xmlns:aop= "http://www.springframework.org/schema/aop" xmlns:tx= "http://www.springframework.org/schema/tx"
xsi:schemaLocatinotallow="http: //www.springframework.org/schema/beans
http: //www.springframework.org/schema/beans/spring-beans-3.2.xsd
http: //www.springframework.org/schema/mvc
http: //www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http: //www.springframework.org/schema/context
http: //www.springframework.org/schema/context/spring-context-3.2.xsd
http: //www.springframework.org/schema/aop
http: //www.springframework.org/schema/aop/spring-aop-3.2.xsd
http: //www.springframework.org/schema/tx
http: //www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!--配置UserServiceImpl -->
<bean id= "userService" class = "com.ys.service.UserServiceImpl" ></bean>
</beans>
|
④、在spring容器中配置 事务处理
在 config/spring 目录下,新建 spring-transaction.xml
<?xml versinotallow= "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:cnotallow= "http://www.springframework.org/schema/context"
xmlns:aop= "http://www.springframework.org/schema/aop" xmlns:tx= "http://www.springframework.org/schema/tx"
xsi:schemaLocatinotallow="http: //www.springframework.org/schema/beans
http: //www.springframework.org/schema/beans/spring-beans-3.2.xsd
http: //www.springframework.org/schema/mvc
http: //www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http: //www.springframework.org/schema/context
http: //www.springframework.org/schema/context/spring-context-3.2.xsd
http: //www.springframework.org/schema/aop
http: //www.springframework.org/schema/aop/spring-aop-3.2.xsd
http: //www.springframework.org/schema/tx
http: //www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!-- 事务管理器 -->
<!-- 对mybatis操作数据事务控制,spring使用jdbc的事务控制类 -->
<bean id= "transactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<!-- 数据源dataSource在spring-dao.xml中配置了 -->
<property name= "dataSource" ref= "dataSource" />
</bean>
<!-- 通知 -->
<tx:advice id= "txAdvice" transaction-manager= "transactionManager" >
<tx:attributes>
<tx:method name= "save*" propagatinotallow= "REQUIRED" />
<tx:method name= "delete*" propagatinotallow= "REQUIRED" />
<tx:method name= "update*" propagatinotallow= "REQUIRED" />
<tx:method name= "insert*" propagatinotallow= "REQUIRED" />
<tx:method name= "find*" propagatinotallow= "SUPPORTS" read-notallow= "true" />
<tx:method name= "get*" propagatinotallow= "SUPPORTS" read-notallow= "true" />
<tx:method name= "select*" propagatinotallow= "SUPPORTS" read-notallow= "true" />
</tx:attributes>
</tx:advice>
<aop:config>
<!-- com.ys.service.impl包里面的所有类,所有方法,任何参数 -->
<aop:advisor advice-ref= "txAdvice" pointcut= "execution(* com.ys.service.impl.*.*(..))" />
</aop:config>
</beans>
|
4、整合 SpringMVC
①、配置前端控制器
在 web.xml 文件中添加如下代码:
<?xml versinotallow= "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:schemaLocatinotallow="http: //java.sun.com/xml/ns/javaee
http: //java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" versinotallow="3.0">
<display-name>SpringMVC_01</display-name>
<!-- 配置前端控制器DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet- class >org.springframework.web.servlet.DispatcherServlet</servlet- class >
<!--springmvc.xml 是自己创建的SpringMVC全局配置文件,用contextConfigLocation作为参数名来加载
如果不配置 contextConfigLocation,那么默认加载的是/WEB-INF/servlet名称-servlet.xml,在这里也就是 springmvc-servlet.xml
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--第一种配置:*. do ,还可以写*.action等等,表示以. do 结尾的或者以.action结尾的URL都由前端控制器DispatcherServlet来解析
第二种配置:/,所有访问的 URL 都由DispatcherServlet来解析,但是这里最好配置静态文件不由DispatcherServlet来解析
错误配置:/*,注意这里是不能这样配置的,应为如果这样写,最后转发到 jsp 页面的时候,仍然会由DispatcherServlet进行解析,
而这时候会找不到对应的Handler,从而报错!!!
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
|
②、配置处理器映射器、处理器适配器、视图解析器
在 config/spring 目录下新建 springmvc.xml文件
<?xml versinotallow= "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:cnotallow= "http://www.springframework.org/schema/context"
xmlns:aop= "http://www.springframework.org/schema/aop"
xmlns:tx= "http://www.springframework.org/schema/tx"
xsi:schemaLocatinotallow="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">
<!--使用mvc:annotation-driven可以代替上面的映射器和适配器
这里面会默认加载很多参数绑定方法,比如json转换解析器就默认加载,所以优先使用下面的配置
-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--批量配置Handler,指定扫描的包全称 -->
<context:component-scan base- package = "com.ys.controller" ></context:component-scan>
<!--配置视图解析器 -->
<bean class = "org.springframework.web.servlet.view.InternalResourceViewResolver" >
</bean>
</beans>
|
③、编写 Handler,也就是 Controller
在 com.ys.controller 包下新建 UserController.java 文件
package com.ys.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.ys.po.User;
import com.ys.service.impl.IUserService;
@Controller
public class UserController {
@Autowired
public IUserService userService;
@RequestMapping ( "/login" )
public ModelAndView login(User user){
ModelAndView mv = new ModelAndView();
User u = userService.selectUserByUsernameAndPassword(user);
//根据用户名和密码查询user,如果存在,则跳转到 success.jsp 页面
if (u != null ){
mv.addObject( "username" , u.getUsername());
mv.addObject( "user" , u);
mv.setViewName( "view/success.jsp" );
} else {
//如果不存在,则跳转到 login.jsp页面重新登录
return new ModelAndView( "redirect:/login.jsp" );
}
return mv;
}
}
|
④、加载 Spring 容器
我们在 classpath/spring 目录下新建了 spring-dao.xml,spring-service.xml,spring-transaction.xml 这些文件,里面有我们配置的 mapper,controller,service,那么如何将这些加载到 spring 容器中呢?
在 web.xml 文件中添加如下代码:
<!-- 加载spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/spring-*.xml</param-value>
</context-param>
<listener>
<listener- class >org.springframework.web.context.ContextLoaderListener</listener- class >
</listener>
|
由于配置文件比较多,我们使用通配符加载的方式。注意:这段代码最好要加在前端控制器的前面。
至此 SSM 三大框架整合就完成了,接下来我们进行测试。
5、测试
在 WebContent 目录下创建 login.jsp 页面,以及 success.jsp页面,如下图:
login.jsp
<%@ page language= "java" cnotallow= "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" cnotallow= "text/html; charset=UTF-8" >
<title>Insert title here</title>
</head>
<body>
<form actinotallow= "login" method= "post" >
<label>账号:</label>
<input type= "text" id= "txtUsername" name= "username" placeholder= "请输入账号" /><br/>
<label>密码:</label>
<input type= "password" id= "txtPassword" name= "password" placeholder= "请输入密码" /><br/>
<input type= "submit" value= "提交" />
<input type= "reset" value= "重置" />
</form>
</body>
</html>
|
success.jsp
<%@ page language= "java" cnotallow= "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" cnotallow= "text/html; charset=UTF-8" >
<title>Insert title here</title>
</head>
<body>
Hello ${user.username}
</body>
</html>
|
1、将项目发布到 tomcat,
2、在浏览器输入:http://localhost:8080/SSMDemo/login.jsp
点击提交:
参数绑定,简单来说就是客户端发送请求,而请求中包含一些数据,那么这些数据怎么到达 Controller ?这在实际项目开发中也是用到的最多的,那么 SpringMVC 的参数绑定是怎么实现的呢?下面我们来详细的讲解。
1、SpringMVC 参数绑定
在 SpringMVC 中,提交请求的数据是通过方法形参来接收的。从客户端请求的 key/value 数据,经过参数绑定,将 key/value 数据绑定到 Controller 的形参上,然后在 Controller 就可以直接使用该形参。
这里涉及到参数绑定组件,那么什么是参数组件,这里可以先理解为将请求的数据转换为我们需要的数据称为参数绑定组件,也就是参数绑定转换器。SpringMVC 内置了很多参数转换器,只有在极少数情况下需要我们自定义参数转换器。
2、默认支持的类型
SpringMVC 有支持的默认参数类型,我们直接在形参上给出这些默认类型的声明,就能直接使用了。如下:
①、HttpServletRequest 对象
②、HttpServletResponse 对象
③、HttpSession 对象
④、Model/ModelMap 对象
Controller 代码:
@RequestMapping ( "/defaultParameter" )
public ModelAndView defaultParameter(HttpServletRequest request,HttpServletResponse response,
HttpSession session,Model model,ModelMap modelMap) throws Exception{
request.setAttribute( "requestParameter" , "request类型" );
response.getWriter().write( "response" );
session.setAttribute( "sessionParameter" , "session类型" );
//ModelMap是Model接口的一个实现类,作用是将Model数据填充到request域
//即使使用Model接口,其内部绑定还是由ModelMap来实现
model.addAttribute( "modelParameter" , "model类型" );
modelMap.addAttribute( "modelMapParameter" , "modelMap类型" );
ModelAndView mv = new ModelAndView();
mv.setViewName( "view/success.jsp" );
return mv;
}
|
表单代码:(截取主要代码)
<body>
request:${requestParameter}
session:${sessionParameter}
model:${modelParameter}
modelMap:${modelMapParameter}
</body>
|
然后访问,页面显示如下:
这里我们重点说一下 Model/ModelMap,ModelMap是Model接口的一个实现类,作用是将Model数据填充到request域,即使使用Model接口,其内部绑定还是由ModelMap来实现
3、基本数据类型的绑定
哪些是基本数据类型,我们这里重新总结一下:
一、 byte ,占用一个字节,取值范围为 - 128 - 127 ,默认是“\u0000”,表示空
二、 short ,占用两个字节,取值范围为 - 32768 - 32767
三、 int ,占用四个字节,- 2147483648 - 2147483647
四、 long ,占用八个字节,对 long 型变量赋值时必须加上 "L" 或“l”,否则不认为是 long 型
五、 float ,占用四个字节,对 float 型进行赋值的时候必须加上“F”或“f”,如果不加,会产生编译错误,因为系统
自动将其定义为 double 型变量。 double 转换为 float 类型数据会损失精度。 float a = 12.23 产生编译错误的, float a = 12 是正确的
六、 double ,占用八个字节,对 double 型变量赋值的时候最好加上“D”或“d”,但加不加不是硬性规定
七、 char ,占用两个字节,在定义字符型变量时,要用单引号括起来
八、 boolean ,只有两个值“ true ”和“ false ”,默认值为 false ,不能用 0 或非 0 来代替,这点和C语言不同
|
我们以 int 类型为例:
JSP 页面代码:
<form actinotallow= "basicData" method= "post" >
<input name= "username" value= "10" type= "text" />
<input type= "submit" value= "提交" >
</form>
|
Controller 代码:
@RequestMapping ( "/basicData" )
public void basicData( int username){
System.out.println(username); //10
}
|
结果是 打印出了表单里面的 value 的值。
注意:表单中input的name值和Controller的参数变量名保持一致,就能完成数据绑定。那么如果不一致呢?我们使用 @RequestParam 注解来完成,如下:
JSP页面代码不变,<input name="username">保持原样,Controller 代码如下
使用注解 @RequestParam ,我们可以使用任意形参,但是注解里面的 value 属性值要和表单的name属性值一样。
问题:我们这里的参数是基本数据类型,如果从前台页面传递的值为 null 或者 “”的话,那么会出现数据转换的异常,就是必须保证表单传递过来的数据不能为null或”",所以,在开发过程中,对可能为空的数据,最好将参数数据类型定义成包装类型,具体参见下面的例子。
4、包装数据类型的绑定
包装类型如Integer、Long、Byte、Double、Float、Short,(String 类型在这也是适用的)这里我们以 Integer 为例
Controller 代码为:
和基本数据类型基本一样,不同之处在于,表单传递过来的数据可以为null或”",以上面代码为例,如果表单中num为”"或者表单中无num这个input,那么,Controller方法参数中的num值则为null。
5、POJO(实体类)类型的绑定
User.java
package com.ys.po;
import java.util.Date;
public class User {
private Integer id;
private String username;
private String sex;
private Date birthday;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this .id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this .username = username == null ? null : username.trim();
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this .sex = sex == null ? null : sex.trim();
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this .birthday = birthday;
}
}
|
JSP页面:注意输入框的 name 属性值和上面 POJO 实体类的属性保持一致即可映射成功。
<form actinotallow= "pojo" method= "post" >
用户id:<input type= "text" name= "id" value= "2" ></br>
用户名:<input type= "text" name= "username" value= "Marry" ></br>
性别:<input type= "text" name= "sex" value= "女" ></br>
出生日期:<input type= "text" name= "birthday" value= "2017-08-25" ></br>
<input type= "submit" value= "提交" >
</form>
|
注意看:这里面我们数据都写死了,直接提交。有Integer类型的,String类型的,Date类型的。
Controller :
@RequestMapping ( "/pojo" )
public void pojo(User user){
System.out.println(user);
}
|
我们在上面代码打个断点,然后输入URL,进入到这个Controller中:
上面是报错了,User.java 的birthday 属性是 Date 类型的,而我们输入的是字符串类型,故绑定不了
那么问题来了,Date 类型的数据绑定失败,如何解决这样的问题呢?这就是我们前面所说的需要自定义Date类型的转换器。
①、定义由String类型到 Date 类型的转换器
package com.ys.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.core.convert.converter.Converter;
//需要实现Converter接口,这里是将String类型转换成Date类型
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
//实现将字符串转成日期类型(格式是yyyy-MM-dd HH:mm:ss)
SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
try {
return dateFormat.parse(source);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//如果参数绑定失败返回null
return null ;
}
}
|
②、在 springmvc.xml 文件中配置转换器
<mvc:annotation-driven conversion-service= "conversionService" ></mvc:annotation-driven>
<bean id= "conversionService" class = "org.springframework.format.support.FormattingConversionServiceFactoryBean" >
<property name= "converters" >
<!-- 自定义转换器的类名 -->
<bean class = "com.ys.util.DateConverter" ></bean>
</property>
</bean>
|
输入 URL,再次查看Controller的形参:
6、复合POJO(实体类)类型的绑定
这里我们增加一个实体类,ContactInfo.java
package com.ys.po;
public class ContactInfo {
private Integer id;
private String tel;
private String address;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this .id = id;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this .tel = tel == null ? null : tel.trim();
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this .address = address == null ? null : address.trim();
}
}
|
然后在上面的User.java中增加一个属性 private ContactInfo contactInfo
JSP 页面:注意属性name的命名,User.java 的复合属性名.字段名
Controller
User对象中有ContactInfo属性,但是,在表单代码中,需要使用“属性名(对象类型的属性).属性名”来命名input的name
7、数组类型的绑定
需求:我们查询出所有User 的信息,并且在JSP页面遍历显示,这时候点击提交按钮,需要在 Controller 中获得页面中显示 User 类的 id 的所有值的数组集合。
JSP 页面:注意用户id的name值定义为 userId
Controller.java
8、List类型的绑定
需求:批量修改 User 用户的信息
第一步:创建 UserVo.java,封装 List<User> 属性
package com.ys.po;
import java.util.List;
public class UserVo {
private List<User> userList;
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this .userList = userList;
}
}
|
第二步:为了简化过程,我们直接从 Controller 中查询所有 User 信息,然后在页面显示
Controller
@RequestMapping ( "selectAllUserAndList" )
public ModelAndView selectAllUserAndList(){
List<User> listUser = userService.selectAllUser();
ModelAndView mv = new ModelAndView();
mv.addObject( "listUser" , listUser);
mv.setViewName( "list.jsp" );
return mv;
}
|
JSP 页面
第三步:修改页面的值后,点击提交
由于我们在 JSP 页面 input 输入框定义的name属性名是 userList[${status.index}].id 这种形式的,这里我们直接用 UserVo 就能获取页面批量提交的 User信息
8、Map类型的绑定
首先在 UserVo 里面增加一个属性 Map<String,User> userMap
第二步:JSP页面,注意看 <input >输入框 name 的属性值
第三步:Controller 中获取页面的属性
9、遇到的问题
①、form表单无法提交input输入框属性设置为 disabled 的内容
比如:
<input type= "text" disabled= "disabled" name= "metadataName" maxlength= "50" placeholder= "这里输入模型英文名称" title= "模型英文名称" "/>
|
具有 disabled="disabled" 的属性,提交到 Controller后,metadataName 的值为null
解决办法:改为 readnotallow="readonly"
readonly:针对input(text / password)和textarea有效,在设置为true的情况下,用户可以获得焦点,但是不能编辑,在提交表单时,输入项会作为form的内容提交。
disabled:针对所有表单元素(select,button,input,textarea等),在设置为disabled为true的情况下,表单输入项不能获得焦点,用户的所有操作无意义,在提交表单时,表单输入项不会被提交。
Json(JavaScript Object Notation),它是一种轻量级数据交换格式,格式简单,易于读写,目前使用特别广泛。那么这篇博客我们主要谈谈在 SpringMVC 中,如何对 json 数据格式进行解析和转换?
1、两种交互模式
上图显示了客户端请求数据的两种格式,一种是 直接请求 json 数据,另一种是 key/value 数据。但是不管请求是哪种数据,为了在前端页面方便对结果进行解析。最终我们都转换为 json 数据格式。
2、导入相应的 jar 包(详情参看源码)
3、在 springmvc.xml 文件中配置 json 转换器
第一种方法:
<mvc:annotation-driven ></mvc:annotation-driven>
|
第二种方法:
<!-- 用于将对象转换为 JSON -->
<bean id= "stringConverter"
class = "org.springframework.http.converter.StringHttpMessageConverter" >
<property name= "supportedMediaTypes" >
<list>
<value>text/plain;charset=UTF- 8 </value>
</list>
</property>
</bean>
<bean id= "jsonConverter" class = "org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" ></bean>
<bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
<property name= "messageConverters" >
<list>
<ref bean= "stringConverter" />
<ref bean= "jsonConverter" />
</list>
</property>
</bean>
|
4、请求为 json 数据测试
这里我们需要注意两个注解:
@ResponseBody把后台pojo转换json对象,返回到页面。
@RequestBody接受前台json数据,把json数据自动封装pojo。
①、jsp 页面
<%@ page language= "java" cnotallow= "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" cnotallow= "text/html; charset=UTF-8" >
<title>SpringMVC和 json 交互</title>
<script type= "text/javascript" src= "${pageContext.request.contextPath}/js/jquery-2.1.4.min.js" ></script>
</head>
<script type= "text/javascript" >
var dataJson = {
'username' : 'Bob' ,
'sex' : '男'
};
function requestJson(){
$.ajax({
type: "POST" ,
url: "${pageContext.request.contextPath}/requestJson" ,
//指定数据格式为 json
contentType: "application/json;charset=UTF-8" ,
data:JSON.stringify(dataJson),
dataType: "json" ,
success:function(data){
console.log(data.username);
console.log(data.sex);
}
});
}
</script>
<body>
<button notallow= "requestJson()" value= "请求是json,返回json" >请求是json,返回json</button>
</body>
</html>
|
②、Controller
package com.ys.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.ys.po.User;
@Controller
public class UserController {
//请求为json,返回json
@RequestMapping ( "/requestJson" )
//@RequestBody将请求信息的json串转成user对象
//@ResponseBody将user对象转成json输出
@ResponseBody
public User requestJson( @RequestBody User user) throws Exception{
System.out.println(user);
return user; //由于@ResponseBody注解,将user转成json格式返回
}
}
|
③、测试
我们访问上面的jsp页面,然后点击按钮,进入到 Controller
然后我们查看返回的数据:
5、请求为 key/value 数据测试
①、JSP 页面
②、Controller
//请求为key/value,返回json
@RequestMapping ( "/requestKeyValue" )
//@RequestBody将请求信息的json串转成user对象
@ResponseBody
public User requestKeyValue(User user) throws Exception{
System.out.println(user);
return user;
}
|
③、测试
然后返回数据:
6、遇到的问题
①、如下代码,由于我们使用 Ajax 提交,我们在 JSP 页面引入了jquery 文件,发现无论使用绝对路径还是相对路径,系统总是找不到这个文件?
<script type= "text/javascript" src= "${pageContext.request.contextPath}/js/jquery-2.1.4.min.js" ></script>
|
原因:因为在web.xml 文件中,对于过滤器的配置是拦截所有请求。所以类似于*.js,或者*.css这样的文件也被拦截了,故访问不到。
解决办法:
第一种办法:我们可以使用上面配置的拦截器只拦截 *.do,或者*.action,而不是 “/”。那么SpringMVC容器将不会拦截*.js,*.css这样的文件。但是这种风格不支持 Restful,建议不采用。
第二种方法:在web.xml中配置拦截器的过滤请求
<!--要写在DispatcherServlet的前面, 让 defaultServlet先拦截请求,这样请求就不会进入Spring了,我想性能是最好的吧。-->
<servlet-mapping>
<servlet-name> default </servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name> default </servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
|
第三种方法:在spingmvc.xml 中配置对静态资源不过滤
<!-- 配置静态文件过滤器 -->
<mvc:resources locatinotallow= "/WEB-INF/css/" mapping= "/css/**" />
<mvc:resources locatinotallow= "/WEB-INF/js/" mapping= "/js/**" />
|
②、也是比较容易犯的错误 415
这个错误产生的原因有很多。我们需要一步一步的排查:
第一步:必须保证导入的 jackson相关的jar包是全的。
第二步:在springmvc.xml文件中的配置的json转换器一定不能缺少,如何配查看本篇博客的第三点
第三步:书写 Ajax 请求时。contentType:"application/json;charset=UTF-8",不要不写 contentType 这个属性
第四步:Ajax传给后台的不要直接传字符串,要转换成json,即 data:JSON.stringify(dataJson),