SpringMVC-详细版
2019-10-23 19:07:52 0 举报
AI智能生成
SpringMVC详解
作者其他创作
大纲/内容
1.介绍及关注重点
Spring mvc和Struts2一样都属于表现层的框架,它是Spring框架的一部分。那么SpringMVC作为一个表现层框架,那么我们应该关注的重点是由哪些呢
(1) 如何接收请求以及接收请求中的参数
(2) 如何返回页面以及向页面传递数据
(3) 如何上传文件
(4) 如何进行JSON数据交换
(5) 如何拦截请求
(6) 如何处理异常
2.SpringMVC环境搭建步骤
(1) 创建web项目
(2) 导入jar
(3) 编写spingmvc.xml配置SpringMVC
主要功能:
1. 配置扫描@Controller注解
2. 配置页面视图解析器
3. 上传文件控制
4. 拦截器配置
5. 异常处理配置
(4) 在web.xml中配置DispatcherServlet前端控制器
分支主题
(5) 编写Controller处理请求
使用@Controller注解让SpringMVC容器管理Bean
使用@RequestMapping配置url请求路径
详细代码参见笔记
3.Spring框架组件
请求流程
分支主题
流程介绍
(1) 用户请求由web.xml中配置的前端控制器DispatcherServlet来获得
分支主题
(2) DispatcherServlet将获得请求url发送给HandlerMapping,HandlerMapping根据url将匹配到的拦截器和@RequestMapping对应的方法(Handler)返回给DispatcherServlet
(3) DispatcherServlet将得到的拦截器和执行方法(Handler)发送给HandlerAdapter去执行
(4) 执行@RequestMapping对应的方法
(5) 方法执行完成后将方法得到的ModelAndView返回给HandlerAdapter
(6) HandlerAdapter将得到的ModelAndView返回给DispatcherServlet
(7) DispatcherServlet将ModelAndView传给ViewReslover视图解析器
(8) ViewReslover视图解析器根据返回的逻辑视图找到物理视图,生成View视图对象,返回给DispatcherServlet
(9) DispatcherServlet将返回的View进行数据渲染,然后响应给用户
组件
DispatcherServlet:前端控制器
描述:整个流程控制的中心,由它调用其它组件处理用户的请求
优点:降低了组件之间的耦合性
HandlerMapping:处理器映射器
描述:根据用户请求url找到相应要执行的拦截器和@RequestMapping对应的方法。
Handler:处理器
描述:@RequestMapping标识的方法。开发人员根据业务编写,相当于Struts2在方法中使用@Action注解一样
注意:声明Handler有多种方式,注解方式、接口方式、配置文件方式。现在都是使用注解方式开发
HandlAdapter:处理器适配器
描述:根据不同声明方式的Handler使用不同的HandlerAdapter适配器来执行
View Resolver:视图解析器
描述:Handler执行完之后会返回一个ModelAndView,视图解析器使用ModelAndView中返回的逻辑视图去找到物理视图,并生成一个View对象
View:视图
描述:View进行数据渲染,最终由DispatcherServlet返回给用户
注意
HandlerMapping、HandlAdapter、View Resolver是SpringMVC的三大组件
需要开发人员开发配置的组件
DispatcherServlet
Handler
View
4.SpringMVC注解和相关配置
@Controller
在SpringMVC的xml中使用<context:component-scan>去扫描@Controller所在的包。让SpringMVC容器装载该包下的@Controller注解的bean
@ResquestMapping
注解在某个方法上,配置一个url与该方法对应。该注解可以声明在类和方法上
使用@RequestMapping配置注解驱动
处理器映射器
分支主题
处理器适配器
分支主题
可以使用注解驱动的方式替换其他两种
<mvc:annotation-driven>
视图解析器配置
配置JSP视图
分支主题
支持多种视图JSP、Freemarker、Velocity
5.SSM整合
SpringMVC
Controller层
Springmvc.xml
(1) 使用<context:component-scan>配置扫描@Controller包
(2) 配置注解驱动<mvc:annotation-driven>
(3) 配置视图解析器
Spring
(1) dao层配置
applicationContext-dao.xml
数据库连接池配置
SqlSessionFactory管理
配置mapper接口包扫描
(2) service层配置
applicationContext-service.xml 扫描@service注解
applicationContext-trans.xml配置service层事务处理
Mybatis
编写SqlMapConfig.xml文件,空文件即可。需要文件头和约束
web.xml
(1) 配置Springmvc的配置前端控制器
分支主题
(2) 配置Spring容器
分支主题
代码参见笔记
6.获取请求参数
(1) 从request对象中获取
在Controller中方法可绑定WEB参数
HttpServletRequest :请求信息
HttpServletResponse:响应信息
HttpSession 一般不绑定,通过request来获取
实例:public ModelAndView itemEdit(HttpServletRequest request, HttpServletResponse response){
.....
}
(2) 在方法中绑定简单参数
简单参数包含基本类型(如:int)和包装类型(如:Integer),还有字符串。
对于使用基本类型时建议改成使用对应的包装类型,因为基本类型有默认值,而包装类型默认值是null
实例:
分支主题
@RequestParam处理简单类型的绑定
value
入参的请求参数名字,如value=“item_id”
required
是否必须,默认是true,表示请求中一定要有相应的参数,否则将报
TTP Status 400 - Required Integer parameter 'XXXX' is not present
defaultValue
默认值,表示如果请求中没有同名参数时的默认值
实例:
分支主题
(3) 绑定pojo
描述:表单中的内容很多的时候可以使用pojo接收数据,要求pojo对象中的属性名和表单中input的name属性一致
页面表单
分支主题
pojo定义
分支主题
对应请求方法中的绑定
分支主题
(4) 绑定包装类型的pojo
页面表单
分支主题
包装类定义
分支主题
对应请求方法中的绑定
分支主题
(5) 绑定数组
描述:在页面删除多条数据时,需要传递一个删除数据的id的数组。那么在请求对应方法中可以用String[]接收,或者pojo的String[]属性接收。两种方式任选其一即可
页面checkbox
分支主题
对应请求方法中的绑定
分支主题
(6) 表单的数据绑定到List(了解)
描述:一般用于批量修改,批量添加
页面表单定义
//第一条数据
<input type="text" name=" itemsList[0].id" value="${item.id}"/>
<input type="text" name=" itemsList[0].name" value="${item.name }"/>
<input type="text" name=" itemsList[0].price" value="${item.price}"/>
//第二条数据
<input type="text" name=" itemsList[1].id" value="${item.id}"/>
<input type="text" name=" itemsList[1].name" value="${item.name }"/>
<input type="text" name=" itemsList[1].price" value="${item.price}"/>
包装pojo定义
分支主题
对应请求方法中的绑定
分支主题
注意:接收List类型的数据必须是pojo的属性,方法的形参为List类型无法正确接收到数据。
解决日期类型参数传递报错
描述:由于Springmvc无法将字符串转换为日期类型,所以页面传递日期类型参数时会报400错误。解决这个问题可以自定义参数绑定
自定义Converter处理日期类型
分支主题
在注解驱动中引入Converter
分支主题
解决中文乱码
post请求
在web.xml中加入过滤器
分支主题
get请求
对参数重新编码
new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
7.SpringMVC与Struts2的区别
(1) springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过虑器
(2) springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例
(3) Struts采用值栈存储请求和响应的数据。springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面
8.@RequestMapping详解
描述:该注解是用来设置某个方法对应的url映射。该注解可配置在方法和类上
value
描述:定义url映射的值,它是数组,可以将多个url映射到同一个方法
窄化请求映射
描述:在@Controller的class上添加@RequestMapping指定通用请求前缀, 限制此类下的所有方法请求url必须以请求前缀开头
在类上设置
分支主题
在方法上设置
分支主题
请求地址:
/item/queryItem
请求方式限定
描述:可以设置方法接收请求的方式 get还是post
限定GET方式
@RequestMapping(method = RequestMethod.GET)
使用POST方式请求报错:
HTTP Status 405 - Request method 'POST' not supported
限定POST方式
@RequestMapping(value="/editItem",method=RequestMethod.GET)
使用GET方式请求报错:
HTTP Status 405 - Request method 'GET' not supported
GET和POST都可以
@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
9.页面和数据返回方式
(1) 返回void,使用传统的request和response
使用request进行转发,并在request中设置参数进行返回
request.getRequestDispatcher("页面路径").forward(request, response);
使用response重定向
response.sendRedirect("url")
使用response响应JSON
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");
(2) 返回ModelAndView
设置返回逻辑试图
(1) 构造返回:
ModelAndView modelAndView = new ModelAndView("/WEB-INF/jsp/itemList.jsp");
(2) 调用方法返回
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/WEB-INF/jsp/itemList.jsp");
向页面返回数据
modelAndView.addObject("itemList", itemList);
方法定义
分支主题
(3) 字符串方式返回(重点)
(1) 返回逻辑视图
描述:controller方法返回字符串可以指定逻辑视图名
分支主题
向页面参数传递
描述:Model/ModelMap主要是用来向页面传递数据,使用Model和ModelMap的效果一样,如果直接使用Model,springmvc会实例化ModelMap
注意:使用Model则可以不使用ModelAndView对象,这个时候使用返回字符串方式来定义返回的逻辑视图。不管是Model还是ModelAndView,其本质都是使用Request对象向jsp传递数据
实例
分支主题
(2) Redirect重定向
描述:Contrller方法返回结果重定向到一个url地址
分支主题
如果要传递参数
/item/queryItem?id=11&name=222
(3) forward转发
描述:controller方法执行后转发到另一个controller方法
分支主题
如果要传递参数
可以使用request来设置参数
request.setAttribute("test","test")
10.SpringMVC异常处理
描述:将项目的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理
自定义异常处理类
在springmvc中配置异常处理类
分支主题
注意:一定要将异常抛出。不要在try{ }catch(){ }中吃掉了异常信息
对于404错误处理
在web.xml中加入
<error-page>
<error-code>404</error-code>
<location>/WEB-INF/views/errors/404.jsp</location>
</error-page>
11.文件上传与下载
描述:SpringMVC使用CommonsMultipartResolver解析器来实现文件上传,该解析器依赖commons-fileupload和commons-io的jar
1). 页面三要素
form表单提交方式 method=post
form表单中必须设置 enctype=”multipart/form-data”
表单中必须有一个指定name属性<input type=”file” name="名称">组件
2). 在Springmvc中配置文件解析器
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--上传文件的最大大小>
<property name="maxUploadSize" value="17367648787"></property>
<!-- 上传文件的编码 -->
<property name="defaultEncoding" value="UTF-8"></property>
</bean>
3). 在方法中使用MultipartFile获取上传文件
分支主题
实例
//商品修改提交
@RequestMapping("/editItemSubmit")
public String editItemSubmit(Items items, MultipartFile pictureFile)throws Exception{
//原始文件名称
String pictureFile_name = pictureFile.getOriginalFilename();
//新文件名称
String newFileName = UUID.randomUUID().toString()+pictureFile_name.substring(pictureFile_name.lastIndexOf("."));
//上传图片
File uploadPic = new java.io.File("F:/develop/upload/temp/"+newFileName);
if(!uploadPic.exists()){
uploadPic.mkdirs();
}
//向磁盘写文件
pictureFile.transferTo(uploadPic);
}
4). 下载代码
java通用方式
@RequestMapping("/download")
public String download(String fileName, HttpServletRequest request,
HttpServletResponse response) {
response.setCharacterEncoding("utf-8");
response.setContentType("multipart/form-data");
try {
String path = "d://download";
InputStream inputStream = new FileInputStream(new File(path
+ File.separator + fileName));
// 根据浏览器的类型处理中文文件的乱码问题:
String agent = request.getHeader("User-Agent");
System.out.println(agent);
if(agent.contains("Firefox")){
fileName = base64EncodeFileName(filename);
}else{
fileName = URLEncoder.encode(filename,"UTF-8");
}
response.setHeader("Content-Disposition", "attachment;fileName="
+ fileName);
OutputStream os = response.getOutputStream();
byte[] b = new byte[1024];
int length;
while ((length = inputStream.read(b)) > 0) {
os.write(b, 0, length);
}
// 这里主要关闭。
os.close();
inputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 返回值要注意,要不然就出现下面这句错误!
//java+getOutputStream() has already been called for this response
return null;
}
public static String base64EncodeFileName(String fileName) {
BASE64Encoder base64Encoder = new BASE64Encoder();
try {
return "=?UTF-8?B?"
+ new String(base64Encoder.encode(fileName.getBytes("UTF-8"))) + "?=";
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
Spring的API实现
@RequestMapping("download")
public ResponseEntity<byte[]> download() throws IOException {
String path="D:\\upload\\图片10.xlsx";
File file=new File(path);
HttpHeaders headers = new HttpHeaders();
//为了解决中文名称乱码问题
String fileName=new String("你好.xlsx".getBytes("UTF-8"),"iso-8859-1");
headers.setContentDispositionFormData("attachment", fileName);
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),
headers, HttpStatus.CREATED);
}
12.JSON数据交换
SpringMVC采用jackson方式进行json数据与java对象相互转换
接收JSON参数——@RequestBody
描述:可以将提交的json字符串直接转换成POJO对象、数组、List,一般在页面使用JSON.stringify(data)的方式就能将json对象变成字符串。同时ajax请求的时候也要指定contentType:"application/json"
ajax请求
分支主题
后台接收
分支主题
public class CustomExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
ex.printStackTrace();
CustomException customException = null;
//如果抛出的是系统自定义异常则直接转换
if(ex instanceof CustomException){
customException = (CustomException)ex;
}else{
//如果抛出的不是系统自定义异常则重新构造一个系统错误异常。
customException = new CustomException("系统错误,请与系统管理 员联系!");
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("message", customException.getMessage());
modelAndView.setViewName("error");
return modelAndView;
}
}
返回JSON数据——@ResponseBody
描述:@ResponseBody注解实现将controller方法返回对象转换为json响应给客户端
ajax请求
分支主题
后台接收
分支主题
页面响应
分支主题
在springmvc.xml配置文件中配置json转换器
<!--注解适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
</bean>
</list>
</property>
</bean>
<mvc:annotation-driven>可以替换上面json转换器
13.RESTful风格请求
描述:Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格,是对http协议的诠释。
资源定位:互联网所有的事物都是资源,要求url中没有动词,只有名词。没有参数
资源操作:使用put、delete、post、get,使用不同方法对资源进行操作。分别对应添加、删除、修改、查询。一般使用时还是post和get
(1) 要求DispatcherServlet前端控制器拦截rest风格请求
分支主题
(2) @PathVariable
URL模板模式映射,@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上
例如:@RequestMapping(value="/ viewItems/{id}"):{×××}占位符,请求的URL可以是“/viewItems/1”或“/viewItems/2”
实例
分支主题
14.拦截器
描述:SpringMVC 的处理器拦截器类似于Servlet 开发中的过滤器Filter,用于对处理器进行预处理和后处理
自定义拦截器
Public class HandlerInterceptor1 implements HandlerInterceptor{
/**
* controller执行前调用此方法
* 返回true表示继续执行,返回false中止执行
* 这里可以加入登录校验、权限拦截等
*/
@Override
Public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generated method stub
Return false;
}
/**
* controller执行后但未返回视图前调用此方法
* 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
*/
@Override
Public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
}
/**
* 只要当前拦截器的preHandle返回true才调用
* 这里可得到执行controller时的异常信息
* 这里可记录操作日志,资源清理等
*/
@Override
Public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}
拦截器中的方法
preHandle
描述:controller执行前调用此方法,返回true表示继续执行,返回false中止执行。
这里一般进行权限验证、登陆控制等等
postHandle
描述:controller必须执行后但未返回视图前调用此方法
afterCompletion
描述:只要当前拦截器的preHandle返回true才调用
配置拦截器拦截的请求路径
针对某一个或者某一类url进行拦截
<mvc:interceptors>
<mvc:interceptor>
<!-- 进行拦截:/login.action请求-->
<mvc:mapping path="/login.action" />
<bean class="com.bybo.aca.web.interceptor.Login"/>
</mvc:interceptor>
<mvc:interceptor>
<!-- 进行拦截:/**表示拦截所有controller -->
<mvc:mapping path="/**" />
<bean class="com.bybo.aca.web.interceptor.Login"/>
</mvc:interceptor>
</mvc:interceptors>
对所有请求进行拦截
<mvc:interceptors>
<!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->
<bean class="com.bybo.aca.web.interceptor.LoginInterceptor"/>
</mvc:interceptors>
对某一类url路径下不拦截某些请求
<mvc:interceptors>
<mvc:interceptor>
<!-- 进行拦截:/**表示拦截所有controller -->
<mvc:mapping path="/**" />
<!-- 不进行拦截 -->
<mvc:exclude-mapping path="/login.action"/>
<bean class="com.bybo.aca.web.interceptor.Login"/>
</mvc:interceptor>
</mvc:interceptors>
15.SpringMVC开发问题
(1) 解决Spring和SpringMVC扫描注解类的冲突问题
描述:这里我们可以使用Spring和SpringMVC中配置<context:component-scan>包扫描注解。那么这里我们能不能混搭呢,也就是说Spring容器扫描所有的注解,那么SpirngMVC会不会有问题?还有很多情况我们下面就讲解
认识Spring容器和SpringMVC容器的关系
SpringMVC作为Spring的一部分,再这里Spring容器是作为父容器,而SpringMVC是子容器。从继承角度来讲,子容器是可以继承父容器的注解bean;比如在SpringMVC扫描的Controller中可以注入Spring容器@Service注解。但是父容器是不能使用子容器注解的bean对象的
情况一
描述:在Spring的配置文件中使用<context:component-scan>扫描所有的@Controller、@Service。SpringMVC容器不做任何扫描
导致问题
启动正常,但是任何请求都不会被拦截,简而言之就是@Controller失效,所有请求都出现404错误
原因:在web.xml中配置前端控制器的时候,无法加载@Controller注解的bean到容器中。所以SpringMVC失效
情况二
描述:在SpringMVC的配置文件中使用<context:component-scan>扫描所有的@Controller、@Service。Spring容器不做任何扫描
导致问题
启动正常,请求也正常,但是事物失效,也就是不能进行回滚
原因:父容器无法获取子容器的bean。导致Spring容器中根本没有@Service。也就是无法对service的bean进行管理。
情况三
描述:在Spring和SpringMVC都使用<context:component-scan>扫描所有的@Controller、@Service
导致问题
启动正常,请求正常,也是事物失效,不能进行回滚
原因:
SpirngMVC中使用在Controller中注入的@Service层的bean是从SpringMVC容器中获取的,不是从父类中获取的,这样就和情况二一样了。
解决方案
解决以上问题:只需要使Spring容器扫描@Service。SpringMVC容器扫描@Controller
方式一
Spring扫描service层所在的包
<context:component-scan base-package="com.service,com.dao">
SpringMVC扫描controller层所在的包
<context:component-scan base-package="com.controller">
方式二:如果包结构比较乱
在Spring扫描包中排除@Controller注解
<context:component-scan base-package="com">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
在SpringMVC只包含@Controller排除@Service注解
<context:component-scan base-package="com">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
(2) 返回JSON数据IE8提示下载问题
方式一:加入配置
<bean id="annotationMethodHandlerAdapter" class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="mappingJacksonHttpMessageConverter" /><!-- json转换器 -->
</list>
</property>
</bean>
<bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<!--防止ie8出现下载,mvc:annotation-driven注释掉,需要把text/json提到最前面,默认返回json,以免所有ajax设置dataType:json -->
<value>text/json;charset=UTF-8</value>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
方式二:配置<mvc:annotation-driven>
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean id="mappingJackson2HttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>text/json;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
(3) 解决DispatcherServlet配置为rest时,也就是设置url-pattern为 /时。静态资源会被拦截的问题
//js静态资源处理
<mvc:resources location="/js/" mapping="/js/**"/>
//css静态资源处理
<mvc:resources location="/css/" mapping="/css/**"/>
//图片静态资源处理
<mvc:resources mapping="/images/**" location="/images/" />
注意:以上映射js、css、图片的目录一定要放在webapp或者webContent目录,
不能放在WEB-INF下
(4) 解决传递日期类型参数报错400问题 ------参见笔记
16.<url-pattern>/</url-pattern>
描述:拦截所有请求,但是会放行 .jsp的请求。但是对于.js .css .png 还是要去拦截
17.<url-pattern>/*</url-pattern>
描述:拦截所有请求,但是在返回页面时还要拦截请求 .jsp 。
收藏
收藏
0 条评论
下一页