SpringMVC的使用
注意,必须要扫描注解和 把Controller层交给Spring容器管理
(一)建立请求URL和控制器之间关系
1.开启SpringMVC对注解支持(在xml里面配置)
mvc:annotation-driven/
2.@RequestMapping注解
@RequestMapping(value="",method={"",""},headers={},params={"",""})
作用:建立请求URL和控制器方法之间的对应关系
@RequestMapping设置的value或者是path就是key
方法就是value ,通过key找value
注意key不能重复,因为重复就不知道找哪个方法
属性:
value:指定映射的内容。(它应该和请求url中的保持一致)。除了value,使用path属性也 可以
值的写法:
在控制器中path(value)属性的取值:写不写/都可以。
method:设置访问方式,常用的method=RequestMethod.POST,和method=RequestMethod.GET
headers:头域,可以设置浏览器支持的格式
params:访问参数设置
注解作用:
用来定义访问的url。可以是方法级别的,也可以是类级别的。两者可以协同工作,缩小选择范围。也可以隐藏代码的真实路径,更加具有安全性和可读性。RequestMapping囊括了更多可配置的参数,不仅仅有提交表单的方式,而且有方法级别响应url请求的地址等信息,更加灵活。
consumes : 意味着请求的HTTP 头的Content-Type 媒体类型与consumes 的值匹配, 才能调用此方法,例如 application/json, text/html;
列子: @GetMapp 工ng(value = ” / consumes/test . json ”, consumes = ” application/json”)
这里映射指定请求的媒体类型是application/ison , 因此,此方法接受一个AJAX 请求。如
果通过浏览器直接访问, 则会看到Spring Boot 报出如下错误,因为通过浏览器访问,通常并没
有设置Content-Type ,所以说null 不支持。
There was an unexpected error (type=Unsupported Media Type , status=415) .
Content type ’ nul l ’ not supported
为了成功调用上述Controller方法,ajax调用必须设置Content -Type 为appli catio n/j s on
produces 指定返回值类型,不但可以设置返回值类型还可以设定返回值的字符编码
1.比如指定返回json数据,但是可以省略,因为有@ResponseBody
2.返回json数据的字符编码为utf-8
@RequestMapping(value = “/pets/{petId}”, produces=“MediaType.APPLICATION_JSON_VALUE;charset=utf-8”)
3.解决跨域问题
@CrossOrigin 注解在controller上面写
@RestController
@RequestMapping(“api/emergency/emergencyevents”)
@CrossOrigin/表示当前控制器支持跨域访问/
public class EmergencyEventsController {
4.配置视图解析器和对注解的支持
视图解析器如果不涉及到页面跳转其实就没有什么意义,比如用ajax异步操作,就不涉及到页面跳转
@DateTimeFormat(pattern = “yyyy:MM:dd HH:mm:ss”)
private Date departureTime;
6.controller
SpringMVC的controller默认就是单例的
如果你bean配置多例了,依赖这个bean的bean也需要多例才行啊(看例子)
在单例的bean中切记声明成员属性(如Map、List集合来缓存数据),是线程不安全的
7.对静态资源放行处理
在SpringMVC.xml里面配置
说明:
location元素:表示webapp目录下(即服务器根目录)的js包下的所有文件;
mapping元素:表示以/js开头的所有请求路径,如/js/a 或者/js/a/b;
该配置的作用是:DispatcherServlet不会拦截以/static开头的所有请求路径,并当作静态资源交由Servlet处理;
8.能访问jsp却无法访问html
原理:
如果将DispatcherServlet请求映射配置为"/",则Spring MVC将捕获Web容器所有的请求,包括静态资源的请求,Spring MVC会将它们当成一个普通请求处理,因此找不到对应处理器将导致错误。
如何让Spring框架能够捕获所有URL的请求,同时又将静态资源的请求转由Web容器处理,是可将DispatcherServlet的请求映射配置为"/"的前提。由于REST是Spring3.0最重要的功能之一,所以Spring团队很看重静态资源处理这项任务,给出了堪称经典的两种解决方案。
先调整web.xml中的DispatcherServlet的配置,使其可以捕获所有的请求:
springmvc org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:spring-mvc.xml 1 springmvc / 通过上面url-pattern的配置,所有URL请求都将被Spring MVC的DispatcherServlet截获.方法1.采用
在springMVC-servlet.xml中配置
一般Web应用服务器默认的Servlet名称是"default",因此DefaultServletHttpRequestHandler可以找到它。如果你所有的Web应用服务器的默认Servlet名称不是"default",则需要通过default-servlet-name属性显示指定:
方法2.采用
首先,
其次,
在接收到静态资源的获取请求时,会检查请求头的Last-Modified值,如果静态资源没有发生变化,则直接返回303相应状态码,提示客户端使用浏览器缓存的数据,而非将静态资源的内容输出到客户端,以充分节省带宽,提高程序性能。
在springMVC-servlet中添加如下配置:
以上配置将Web根路径"/"及类路径下 /META-INF/publicResources/ 的目录映射为/resources路径。假设Web根路径下拥有images、js这两个资源目录,在images下面有bg.gif图片,在js下面有test.js文件,则可以通过 /resources/images/bg.gif 和 /resources/js/test.js 访问这二个静态资源。
假设WebRoot还拥有images/bg1.gif 及 js/test1.js,则也可以在网页中通过 /resources/images/bg1.gif 及 /resources/js/test1.js 进行引用。
9.通过ip端口映射本地的文件夹路径
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class UploadFilePathConfig extends WebMvcConfigurerAdapter {
/*配置浏览器通过url访问本地文件夹下的图片等等,
以下配置的是本地文件夹地址是"e://JavaExploit/"
程序员可以通过访问 http://localhost:9999/file/6baf3b6f.jpg 在浏览器上显示图片
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/file/**").addResourceLocations(“file:” + “e://JavaExploit/”);
}
}
(二)@ResponseBody对json的处理
使用:需要导入依赖,依赖在使用的下面
java代码
@ResponseBody
@RequestMapping("/hvxm")
public Lmxi hvxm() {
Lmxi lmxi = this.accountService.hvxm(2);
System.out.println("lmxi = " + lmxi);
return lmxi;
}
控制台
前台打印是
//***************************************
需要导入依赖(2.7.0以下的用不了):
com.fasterxml.jackson.core
jackson-databind
2.9.0
com.fasterxml.jackson.core
jackson-annotations
2.9.0
com.fasterxml.jackson.core
jackson-core
2.9.0
s
@ResponseBody作用
ResponseBody 注解直接将返回的对象输出到客户端,如果是字符串, 则直接返回: 如果不是,则默认使用Jackson 序列化成JSON 字符串后输出。
作用:作用于方法上,将方法返回的对象,通过HttpMessageConverter接口转换成指定格式的数据: 比如json和xml等等,通过Response想应给客户端(说白了就是将方法返回的数据转成json响应给客户端)
(三)Jackson的API
对象转map
Map map = objectMapper.convertValue(userInfoEntity, Map.class);
map转对象
UserInfoEntity userInfoEntity1 = objectMapper.convertValue(map, UserInfoEntity.class);
list转json
List testData = this.testDao.findAll();
String testDataJson = new ObjectMapper().writeValueAsString(testData);
对象转json
(四)文件上传
需要引入坐标依赖:
commons-io
commons-io
2.5
commons-fileupload
commons-fileupload
1.3.2
jsp页面
注意:
method=“post” enctype=“multipart/form-data” 不能改变 请求也不能改变
name=“uploadFile” 不能改变,因为SpringMVC内部会用这个东西
}
还需要在SpringMVC.xml里面配置文件上传解析器
SpringMVC核心
要想引入SpringMVC做表现层开发,最基本的需要完成两件事:
1. 配置前端控制器。
2. 开发后端控制器。
(一)控制器和解析器
前端控制器
前端控制器(DispatcherServlet): org.springframework.web.servlet.DispatcherServlet,它是SpringMVC接收web请求的第一入口,也是唯一入口。这是一个servlet对象,因此需要在web.xml中进行配置。
DispatcherServlet启动后会立刻去找SpringMVC的配置文件,然后根据配置文件中的内容进行加载和扫描
还需要配置加载SpringMVC配置文件
后端控制器
用@Controller注解将一个java类声明为SpringMVC后端控制器
注意!!! 需要配置扫描包
@RequestMapping 定义后端控制器的方法
视图解析器
异常解析器
具体看day95 07视频 08视频自定义异常
(二)获取页面参数三种方法
jsp页面,点击submi提交请求到后台,后台需要获取页面“用户名”与“密码”输入框中的值
1.传统的 request.getParameter(“uname”);//同Servlet一样,获取页面属性名叫uname的值
2. 注解机制@RequestParam(“uname”)String username——获取页面属性名叫"uname"的值,用String类型接收,变量名叫username
3.JavaBean自动装配机制 创建一个实体类,实体类的属性需要和前台控件name属性值一致
(三)模型对象(Model和ModelAndView)
Model和ModelAndView 可以给页面赋值
模型对象,是SpringMVC默认支持的一种形参类型,由SpringMVC自动创建,使用时只需定义在方法形参上即可。
作用:可以向Model参数中添加页面需要的变量(属性名)和结果值(属性值),SpringMVC会负责将Model中的变量赋值给request对象,这样JSP就可以用EL表达式从request对象中取得这个变量(属性名)的数据了。(赋值request对象就是调用了request.setAttribute(属性名, 属性值)方法完成的。)
ModelAndView形参类似Model,但额外提供了一个视图名称
注意:Model不能在方法中自己构造,因为Model本身是一个接口,所以只能由SpringMVC帮助实例化
(四)参数绑定
基本参数绑定
Springmvc作为表现层框架,是后端程序的入口,它负责接收页面HTTP请求(POST/GET)过来的参数,参数可以是【url后面拼接的】,也可以是【页面控件的值】,也可以是【hidden变量的值】,也可以是【ajax提交的js对象】,也可以是【ajax提交的json字符串】等等。这也体现了本课开始时说的SpringMVC的第一个作用:“接收请求中的参数”。
1.默认支持的参数类型:HttpServletRequest,HttpServletResponse,HttpSession,
Model(ModelAndView)
2.Java简单类型:int,long,double,String,Long,Double,Boolean,Integer等
3.POJO类型
4.POJO的包装类型-QueryVo
简单的传参规范,页面控件提交的name属性必须等于controller方法的形参名.(适合单个和少数的参数的请求)
pojo类型页面提交的控件name属性值必须等于Controller方法形参对象中的属性名。(适合多参数、不固定参数个数的请求。)
QueryVo页面提交控件的name属性值必须等于Controller方法形参对象中的属性.属性.属性…。(适合综合查询条件参数的传递。)
高级参数绑定
数组类型的参数可以传递一批相同的数据到Controller的方法中。
应用场景:批量删除
功能分解: 前端 能选中多个商品,能提交选中的多个商品
后端 能接收选中商品的id; 进行删除处理
提交相同名称的参数时候,SpringMVC会把它们处理成数组
传参规范:页面提交的控件name属性值必须等于Controller方法数组形参名或者形参对象中的数组属性名。
方式: 1.直接在形参里面传递数组参数
2.在VO里面传递数组参数
List集合类型
可以利用list集合类型的参数传递多条数据进行批量处理,比如批量更新
应用场景:实现商品数据的批量修改
需求分析:要想实现商品数据的批量修改,需要在商品列表中可以对商品信息进行 修改,并且可以批量提交修改后的商品数据。提交的数据应该是一个 List。
功能分解:
前端:1)列表改成input输入框;2)定义改好的input框的name属性;
后端:1)能接收到提交过来的更新数据;2)批量更新处理
<%@ page language=“java” contentType=“text/html; charset=UTF-8”
pageEncoding=“UTF-8”%>
<%@ taglib uri=“http://java.sun.com/jsp/jstl/core” prefix=“c” %>
<%@ taglib uri=“http://java.sun.com/jsp/jstl/fmt” prefix=“fmt”%>
商品列表:
附:
varStatus属性常用参数总结下:
${status.index} 输出行号,从0开始。
${status.count} 输出行号,从1开始。
${status.current} 当前这次迭代的(集合中的)项
${status.first} 判断当前项是否为集合中的第一项,返回值为true或false
${status.last} 判断当前项是否为集合中的最后一项,返回值为true或false
begin属性、end属性、step属性分别表示:起始序号,结束序号,跳跃步伐。
其中[]被encode了,仔细辨认可以看出来。
提交名称开头相同,又带有下标和后缀名的参数,SpringMVC会根据形参中的List属性的定义,按照这个List属性中泛型的类型进行参数绑定。
@CookieValue(了解)
作用:用于指定cookie的名称的值传给控制器方法参数
属性:
value:指定cookie名字
required:是否必须有此cookie
@SessionAttributes(用处不大,还不如用request自带的session了)
作用:用于实现多次请求的数据共享。
就是把数据存入Session域中
属性:
value:用于指定存入session域中的key
types:用于指定存入session域中的数据类型
@SessionAttributes(value= {“username”,“password”},types=Integer.class)
它只能声明类上。
@ModelAttribute(没有,使用效率太低)
写在方法上意思是在别的控制器执行之前先执行被这个注解标注的方法,返回值可以共享到别的方法(返回值的东西加到map里面.这个map是ModelMap ,也是Model)
写在参数名上就是指定在map中哪个key给这个对象赋值
SpringMVC附属
(一)拦截器使用&概念
1.概念
详细看这个文档
2.使用
拦截器使用
先编写一个拦截器类 必须implements HandlerInterceptor(import org.springframework.web.servlet.HandlerInterceptor;)
然后开始根据需求重新方法
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
如果不配置,SpringMVC无法知道这里有个拦截器
/
public class MyInterceptor1 implements HandlerInterceptor {
/*
* 此方法是拦截器的拦截方法,它在控制器方法执行之前执行。
* 此方法return true的时候表示放行。return false 表示不放行
/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(“MyInterceptor1.preHandle 执行了”);
//return false; //不放行
return true; //表示放行
}
/*
* 放行之后,控制器方法执行完成之后,此方法执行。
* 它可以对响应的内容进行处理
* 此方法执行时,视图还没有执行。
/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(“MyInterceptor1.postHandle执行了”);
}
/*
* 它是在视图执行完成之后执行。
* 只有当前连接器的preHandle返回true的时候,它才会执行
* 它可以做一些清理的操作
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(“MyInterceptor1.afterCompletion执行了”);
}
}
在SpringMVC的配置文件配置拦截器(告诉SpringMVC我这里有个拦截器,不配置的话无法使用)
SpringMVC.xml
mvc:interceptors
mvc:interceptor
mvc:interceptor
结果:
(二)设置放行路径
mvc:interceptors
mvc:interceptor
/appUser/examineUserNickNameExist
/**
校验token的拦截器
*/
public class TokenInterceptor implements HandlerInterceptor {
// 这里有getset方法省略了
private List exceptUrls;/放行url集合/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (exceptUrls.contains(request.getRequestURI())) { //直接放行
return true;
}
return true;
}
(三)自定义异常使用&概念
自定义异常使用
先自定义异常类
/**
*自定义异常类
*/
public class User2Exception extends Exception {
private String message;
public User2Exception(String message) {
this.message = message;
}
@Override
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
controller层方法
/**
/**
异常概念
系统中异常主要包括两类:
1.预期异常
a)通过捕获异常从而获取异常信息
2.运行时异常RuntimeException,
a)主要通过规范代码开发,测试通过手段减少运行时异常的发生
系统的dao,service,controller 出现都通过throw Exception 向上抛出,最后由SpringMVC DispatcherServlet (前端控制器)交由异常处理器进行异常处理
RESTful风格代码
(一)使用
1.RESTful基本增删改查模版
2.SpringMVC对RESTful的支持
修改拦截的URL路径
想要SpringMVC支持RESTful,需要在web.xml中修改可以接收的URL:.action改成/,这样的配置会让DispatcherServlet拦截有所的url,只放行.jsp的URL。
springmvc
/
因为除了.jsp的URL以外,其余的URL都会被拦截,那js、css等资源文件的URL怎么办?
配置放行的资源文件
【SpringMVC.xml】
此处可以试一试:
启动tomcat后,直接访问一个js文件,应该是可以访问到的,但是如果把这个配置注视掉,再启动tomcat后,就访问不到了。
到此SpringMVC的RESTful配置完成。剩下要做的就是把我们的系统从传统URL改造成RESTful风格。
3.根据RESTful特征改造URL
在我们现在的代码示例中,传统的URL:
http://localhost:8080/ssm-2/items/list.action(查询,GET)
http://localhost:8080/ssm-2/items/itemEdit.action?id=1(查询,GET)
http://localhost:8080/ssm-2/items/itemUpdate.action(更新,POST)
http://localhost:8080/ssm-2/items/sendJson.action(模拟删除,POST)
把上面url变成RESTful样式如下:
http://localhost:8080/ssm-2/items/list(查询,GET)
http://localhost:8080/ssm-2/items/detail/1(查询,GET)
http://localhost:8080/ssm-2/items/detail(更新,PUT)
http://localhost:8080/ssm-2/items/detail(模拟删除,DELETE)
RESTful系统中@RequestMapping注解的作用非常大:
@RequestMapping(value=“url”, method=RequestMethod.POST/GET/DELETE/PUT), 用注解中的method属性来限定请求的类型,这样对网络资源的增删改查的目的也就表现出来了.
下面是演示crud
然后写个拦截器在web.xml
4.返回值问题body和build
有返回值:
有返回值的时候写 body() 如果是响应状态码是200,括号里面写返回值类型
是500就写body(null);
没有返回值
如果没有返回值就写Void 同时返回build()
5.rest风格url传参问题
使用@PathVariable注解
注解作用:用于方法参数上,表示参数的值来源于URL路径,原因是传统的RESTful风格无法使用 request.getParameter方法来获取参数了.
通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx”) 绑定到操作方法的入参中。
(二)概念问题
1.不同HTTP请求类型的含义(常用的)
GET
从服务器取回数据(只是取回数据,而不会产生其他的影响)。这是一个幂等的方法(译者注:使用相同的参数重复执行,应该能够获取到相同的结果)。下面是一个使用GET请求从服务器获取id为123的书的例子:
GET /books/123
POST
POST请求通常用来创建一个实体,也就是一个没有ID的资源。一旦这个请求成功执行了,就会在HTTP请求的响应中,返回这个新创建的实体的id。我们通常用它来上传文件或者表单。比如,下面这个URL将会在服务器上创建一本新书:
POST /books/
PUT
PUT请求和POST请求类似,但是一般用来更新一个已有的实体。通过把已经存在的资源的ID和新的实体用PUT请求上传的服务器,来更新资源。比如,下面这个URL将会替换掉服务器上的ID为123的书:
PUT /books/123
DELETE
DELETE方法用来从服务器上删除资源。和PUT类似,你需要把要删除的资源的ID上传给服务器。比如下面这个URL可以用来删除服务器上ID为123的书:
DELETE /books/123
2.基本简介
restful并不是新的技术,只是一种代码的风格,并不是强制要求,遵守了就是restful风格,不遵守就不是.和传统的区别就是:请求地址一模一样,但是请求方式改变就分别变为crud,简单来说restful通过响应状态码来区分是否是增删改查.
URL改成RESTful风格后变得更加简洁了
3.常用的四种响应状态码的接口规范
GET
安全且幂等
获取表示
变更时获取表示(缓存)
200(OK) - 表示已在响应中发出
204(无内容) - 资源有空表示
301(Moved Permanently) - 资源的URI已被更新
303(See Other) - 其他(如,负载均衡)
304(not modified)- 资源未更改(缓存)
400 (bad request)- 指代坏请求(如,参数错误)
404 (not found)- 资源不存在
406 (not acceptable)- 服务端不支持所需表示
500 (internal server error)- 通用错误响应
503 (Service Unavailable)- 服务端当前无法处理请求
POST
不安全且不幂等
使用服务端管理的(自动产生)的实例号创建资源
创建子资源
部分更新资源
如果没有被修改,则不过更新资源(乐观锁)
200(OK)- 如果现有资源已被更改
201(created)- 如果新资源被创建
202(accepted)- 已接受处理请求但尚未完成(异步处理)
301(Moved Permanently)- 资源的URI被更新
303(See Other)- 其他(如,负载均衡)
400(bad request)- 指代坏请求
404 (not found)- 资源不存在
406 (not acceptable)- 服务端不支持所需表示
409 (conflict)- 通用冲突
412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)
415 (unsupported media type)- 接受到的表示不受支持
500 (internal server error)- 通用错误响应
503 (Service Unavailable)- 服务当前无法处理请求
PUT
不安全但幂等
用客户端管理的实例号创建一个资源
通过替换的方式更新资源
如果未被修改,则更新资源(乐观锁)
200 (OK)- 如果已存在资源被更改
201 (created)- 如果新资源被创建
301(Moved Permanently)- 资源的URI已更改
303 (See Other)- 其他(如,负载均衡)
400 (bad request)- 指代坏请求
404 (not found)- 资源不存在
406 (not acceptable)- 服务端不支持所需表示
409 (conflict)- 通用冲突
412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突)
415 (unsupported media type)- 接受到的表示不受支持
500 (internal server error)- 通用错误响应
503 (Service Unavailable)- 服务当前无法处理请求
DELETE
不安全但幂等
删除资源
200 (OK)- 资源已被删除
301 (Moved Permanently)- 资源的URI已更改
303 (See Other)- 其他,如负载均衡
400 (bad request)- 指代坏请求
404 (not found)- 资源不存在
409 (conflict)- 通用冲突
500 (internal server error)- 通用错误响应
503 (Service Unavailable)- 服务端当前无法处理请求
4.认识REST
REST本质上是使用URL来访问资源种方式。众所周知,URL就是我们平常使用的请求地址了,其中包括两部分:请求方式与请求路径,比较常见的请求方式是GET与POST,但在REST中又提出了几种其它类型的请求方式,汇总起来有六种:GET、POST、PUT、DELETE、HEAD、OPTIONS。尤其是前四种,正好与CRUD(Create-Retrieve-Update-Delete,增删改查)四种操作相对应,例如,GET(查)、POST(增)、PUT(改)、DELETE(删),这正是REST与CRUD的异曲同工之妙!需要强调的是,REST是“面向资源”的,这里提到的资源,实际上就是我们常说的领域对象,在系统设计过程中,我们经常通过领域对象来进行数据建模。
REST是一个“无状态”的架构模式,因为在任何时候都可以由客户端发出请求到服务端,最终返回自己想要的数据,当前请求不会受到上次请求的影响。也就是说,服务端将内部资源发布REST服务,客户端通过URL来访问这些资源,这不就是SOA所提倡的“面向服务”的思想吗?所以,REST也被人们看做是一种“轻量级”的SOA实现技术,因此在企业级应用与互联网应用中都得到了广泛应用。
下面我们举几个例子对REST请求进行简单描述:
可见,请求路径相同,但请求方式不同,所代表的业务操作也不同,例如,/advertiser/1这个请求,带有GET、PUT、DELETE三种不同的请求方式,对应三种不同的业务操作。
虽然REST看起来还是很简单的,实际上我们往往需要提供一个REST框架,让其实现前后端分离架构,让开发人员将精力集中在业务上,而并非那些具体的技术细节。下面我们将使用Java技术来实现这个REST框架,整体框架会基于Spring进行开发。
SpringMVC概念
1.SpringMVC组件
自己总结的:
前端控制器DispatcherServlet
SpringMVC接收web请求的入口,作用是接受请求,响应结果,返回的可以是json,String等数据类型,也可以是页面(Model) 也相当于(BaseServlet)
HandlerMapping处理器映射器
SpringMVC.xml配置文件 配置
根据我们在浏览器输入的URL去查找处理器(handler),一般通过xml配置或者注解进行查找,还有实现接口方式查找
处理器handler
@Controller标注的Java类就是后端控制器,
后端控制器使用@RequestMapping修饰的方法都是一个handler对象,
handler对象都是程序员自己编写的
HandlerAdapter(处理器适配器)
处理器适配器负责执行找到的Handler对象
执行handler,将handler的返回值和逻辑视图名字符串返回给前端控制器
其实作用就是匹配方法的,控制器有很多方法
1.是自己写一个类
2.继承父类
3.实现一个接口
三个里面方法不一样,需要判断一下,然后就是转换成同一个型号,如下图所示,不同的类型的接口转成一个USB接口.就实现USB的代码.
适配器模式:
就是把不同来源的代码转换一下一样的
然后把相同的代码抽取出来,
ViewReslover视图解析器
负责解析出视图文件的物理路径,并根据这个路径生成视图View对象(常见的有JSP,FreeMark等)我们最常见的就是jsp
2.框架流程解析(SpringMVC)
1.Tomcat启动 开始加载web.xml
Servlet就会创建(配置了load)
然后启动容器
3.浏览器发送请求,经过前端控制器(DispatcherServlet),截取出来URL路径,
然后找到对应的控制器方法(从@RequestMapping找)然后执行method.invoke方法
然后通过方法的 return 的视图名,
找视图解析器,通过加预先设定好的前缀和后缀去找页面
然jsp会响应给浏览器
3.乱码问题
具体的看 getpost乱码看第一天笔记
post乱码问题:
在web.xml中加入:
.
. CharacterEncodingFilter
. org.springframework.web.filter.CharacterEncodingFilter
.
. encoding
. utf-8
.
.
.
. CharacterEncodingFilter
. /*
.
以上可以解决post请求乱码问题。
get乱码
对于get请求中文参数出现乱码解决方法有两个:
修改tomcat配置文件添加编码与工程编码一致,如下:
.
另外一种方法对参数进行重新编码:
.String userName = new String(request.getParamter(“userName”).getBytes(“ISO8859-1”),“utf-8”)
ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码
4.请求转发和重定向区别
请求转发:【forward:】开头的字符串,后面跟转发的URL路径,URL如果有后缀(.action)要加上。
重定向:【redirect:】开头的字符串,后面跟重定向的URL路径,URL如果有后缀(.action)要加上。
注意:关键字后面的冒号是半角。
请求转发是后台程序方法之间跳转时使用的,由于是后台之间的跳转,因此浏览器中URL不发生改变,这也说明还是在同一个Request请求中,因此转发后的方法仍然可以接收转发前从浏览器提交上来的Request对象的HTTP参数。
重定向相当于再次从浏览器发起一个新的Request请求,由于是从前台重新发起的,因此浏览器中的URL发生改变。由于不是同一个Request请求,因此重定向后的方法不能接收重定向前从浏览器提交上来的HTTP参数。
/**
重定向不能携带参数,怎么解决问题,可以用model来解决这个问题,
为什么重定向可以使用Model传递参数?
因为重定向的字符串返回时,SpringMVC看到是redirect开头最终由视图解析器解析后会生成一个专门处理重定向的视图View对象:org.springframework.web.servlet.view.RedirectView,这个View会把前端控制器给它的Model数据放到新Request对象的Parameter(HTTP参数)中,这样重定向后就会得到参数了。
如果是非重定向的字符串返回(逻辑视图名或请求转发)时,视图解析器会生成普通的视图View对象:org.springframework.web.servlet.view.InternalResourceView,这个View会把前端控制器给它的Model数据放到同一个Request对象的Attribute(属性)中。
因此大家在使用SpringMVC时要善用Model(ModelAndView)。
Controller方法的返回jsp页面是请求转发还是重定向?
Jsp本身就是一个Servlet对象,Controller方法在向jsp页面跳转后URL并没有发生改变,仍然是提交给方法时候的URL,而且放置在Model(ModelAndView)参数中的数据会被SpringMVC放置到Request对象中,也都在Jsp页面通过EL表达式得到了,这说明它们是一个Request对象,EL表达式通过属性名从Request对象的Attribute中取得了结果值。
因此跳转到JSP页面是请求转发而不是重定向。
Request对象的Parameter和Attribute
Request域指的是Attribute, 我们model底层把数据放到request域里面的attribute里面(相当于调用setAttribute方法放进去了,前台jsp通过EL表达式从域里取值(从attribute里面)).
Request对象的Parameter是指从请求发起端提交上来的参数,出于安全的考虑,这些参数在我们的后台java程序中是无法篡改的。因此只有request.getParameter(“参数名”)方法,但没有setParamete()方法。
Request对象的Attribute是指后台方法与方法对象与对象之间请求转发时,传递数据的,这个可以在后台方法中随便进行set/getAttribute()。
因此,不要混淆这两个集合的用途和概念。
5.SpringMVC与Struts2的主要区别?
①springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过虑器。
②springmvc是基于方法开发,传递参数是通过方法形参,可以设计为单例或多例(建议单例), struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
③Struts采用值栈存储请求和响应的数据,通过OGNL存取数据,
springmvc通过参数解析器是将request对象内容进行解析成方法形参,将响应数据和页面封装成ModelAndView对象,最后又将模型数据通过request对象传输到页面。 Jsp视图解析器默认使用jstl。
6.MVC模式的优点与不足
MVC模式早在上个世纪70年代就诞生了,直到今天它依然存在,可见生命力相当之强。MVC模式最早用于Smalltalk语言中,最后在其它许多开发语言中都得到了很好的应用,例如,Java中的Struts、Spring MVC等框架。正是因为这些MVC框架的出现,才让MVC模式真正落地,让开发更加高效,让代码耦合度尽量减小,让应用程序各部分的职责更加清晰。
既然MVC模式这么好,难道它就没有不足的地方吗?我认为MVC至少有以下三点不足:
1.每次请求必须经过“控制器->模型->视图”这个流程,用户才能看到最终的展现的界面,这个过程似乎有些复杂。
2.实际上视图是依赖于模型的,换句话说,如果没有模型,视图也无法呈现出最终的效果。
3.渲染视图的过程是在服务端来完成的,最终呈现给浏览器的是带有模型的视图页面,性能无法得到很好的优化。
为了使数据展现过程更加直接,并且提供更好的用户体验,我们有必要对MVC模式进行改进。不妨这样来尝试,首先从浏览器发送AJAX请求,然后服务端接受该请求并返回JSON数据返回给浏览器,最后在浏览器中进行界面渲染。
改进后的MVC模式如图2所示。
也就是说,我们输入的是AJAX请求,输出的是JSON数据,市面上有这样的技术来实现这个功能吗?答案是REST。
REST全称是Representational State Transfer(表述性状态转移),它是Roy Fielding博士在2000年写的一篇关于软件架构风格的论文,此文一出,威震四方!国内外许多知名互联网公司纷纷开始采用这种轻量级的Web服务,大家习惯将其称为RESTful Web Services,或简称REST服务。]
如果将浏览器这一端视为前端,而服务器那一端视为后端的话,可以将以上改进后的MVC模式简化为以下前后端分离模式,如图3所示。
可见,有了REST服务,前端关注界面展现,后端关注业务逻辑,分工明确,职责清晰。那么,如何使用REST服务将应用程序进行前后端分离呢?我们接下来继续探讨,首先我们需要认识REST。
7.SpringMVC为何能准确的找到http请求controller的某个方法来处理
我们需要给一个类加注解@Controller,然后定义一个加了注解@RequestMapping的方法,这样Spring容器就可以准确找到对应的方法了.
在Spring MVC里,有一专门处理请求映射的接口HandlerMapping,查看此接口的实现类:
其中,RequestMappingHandlerMapping是我们需要关注的。我们首先看一下RequestMappingHandlerMapping的抽象父类AbstractHandlerMethodMapping,省略其他方法,先关注这两个相关核心方法
可以看到AbstractHandlerMethodMapping实现了InitializingBean接口,在Spring初始化bean的时候,如果bean实现了InitializingBean接口,会自动调用afterPropertiesSet方法。initHandlerMethods方法,顾名思义是初始化HandlerMethods,查看它是被afterPropertiesSet方法调用,这个方法代表bean在容器中被初始化的时候,会去执行initHandlerMethods方法。
那initHandlerMethods方法具体做了什么事情?大概看一下方法内部的业务,首先拿到容器里的所有bean名称放进数组beanNames中;然后遍历数组,拿到每一个bean的类型beanType,对每一个beanType做了一个判断isHandler(beanType),查看此方法的实现,即进入RequestMappingHandlerMapping中:
·很容易看出来,是去判断该类是否加了注解@Controller或@RequestMapping。点进去查看AnnotatedElementUtils.hasAnnotation方法的实现
所以我们判断一个类上是否加了什么注解,可以这么写:
判断完类上加了注解@Controller或者@RequestMapping后,看到继续执行了detectHandlerMethods方法:
这个方法筛选出了类中加了注解@RequestMapping的方法,放进Map集合methods中,紧接着去遍历每一个method,进入registerHandlerMethod方法,注册到映射注册表mappingRegistry中,其中就是一些Map。
至此,我们就明白了在Spring初始化bean的时候,就把所有的加了@Controller/@RequestMapping的类里面的加了@RequestMapping的方法放进了map中,当http请求来临时,直接去map中迅速拿到对应信息。
JSR-303
(一)使用
1.验证bean的属性的注解
空检查
。@Null , 验证对象是否为空;
。@NotNull , 验证对象不为空:
。@NotBlank , 验证字符串不为空或者不是空字符串, 比如””和””都会验证失败:
。@NotE mpty , 验证对象不为null ,或者集合不为空。
长度检查
。@S ize(min=, max=),验证对象长度,可支持字符串、集合:
。@Length , 字符串大小。
数值检测
。@Min ,验证数字是否大于等于指定的值:
。@Max ,验证数字是否小于等于指定的值;
。@Digits , 验证数字是否符合指定格式,如@ Digits(integer=9 ,台action=2):
其他
。@E mail , 验证是否为邮件格式,为null 则不做校验;
。@Pa忧em , 验证String 对象是否符合正则表达式的规则。
2.group
不同的业务逻辑会有不同的验证逻辑,比如更新的时候,id必须不是null ,但是新增的时候,id必须是null.