springMVC:基于spring的一个框架,实际上就是spring的一个模块,专门做web开发的
理解为servlet的一个升级
springMVC能够创建对象,放到容器中(springMVC容器),springMVC容器中放的是控制器对象
@Controller创建控制器对象,把对象放在springMVC容器中,把创建的对象当作控制器使用,这个控制器对象能接受用户的请求,显示处理结果,就当做是一个servlet使用
@Contorller注解创建的是一个普通对象,不是servlet,springMVC赋予控制器对象一些额外的功能
springMVC中有一个对象是servlet:DispatherServlet:负责接受请求,之后DiapatherServlet把请求转发给Controller对象,最后是Controller对象处理
- 加入的依赖
<!-- servlet依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- springmvc依赖,带入spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
- springmvc.xml中声明组件扫描器
<!-- 声明组件扫描器-->
<context:component-scan base-package="com.yixia.controller"/>
<!-- 声明springmvc框架中的视图解析器,帮助开发人员配置视图文件的路劲-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀:视图文件的路径-->
<property name="prefix" value="/WEB-INF/view/"/>
<!-- 后缀,视图文件的扩展名-->
<property name="suffix" value=".jsp"/>
</bean>
- web.xml中创建中央调度器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--声明,注册springmvc的核心对象DispatherServlet
需要在tomcat服务器启动后,创建DispatherServlet对象的示例,同时创建springmvc对象,
读取springmvc的配置文件,当用户发送请求时,就可以访问对象了
-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 自定义springmvc读取的配置文件的位置-->
<init-param>
<!-- springmvc的配置文件的位置的属性-->
<param-name>contextConfigLocation</param-name>
<!-- 指定自定义文件的位置-->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 在tomcat启动后,创建servlet对象
load-on-startup:表示tomcat启动后创建对象的顺序,他的值时整数,数值越小,tomcat创建对象的时间越早
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- 使用框架的时候url-pattern可以使用两种值
1.使用扩展名方式,语法*。xxxx,xxxx是自定义的扩展名,常用的方式是*.do,*.action,*.mvc等
2.使用斜杠"/"
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
- 创建普通Controller类
@Controller
public class MyController {
/**
* 处理用户提交的请求,sprngmvc中是使用方法来处理的
* 方法是自定义的额,有多种放回值,多种参数,方法名自定义
*/
/**
* 准备使用doSome方法处理some.do请求
* @RequestMapping:请求映射,作用是把一个请求地址和一个方法绑定在一起
* 一个请求指定一个方法处理
* 属性:1.value是String,表示请求的url地址的(some.do)
* value必须是唯一的,不能重复,在使用是,推荐地址以“/"
* 位置:1.在方法的上面,常用的
* 2。在类的上面
* 说明:使用RequestMapping修饰的方法叫做处理器方法或者控制器方法
* 使用@RequestMapping修饰的方法可以处理请求,类似于Servlet中的doGet,doPost
* @return
* ModelAndView:表示本次的处理结果
* model:数据,请求处理完成后,要显示给用户的数据
* Viem:视图,比如jsp等
*
*/
@RequestMapping(value = "/some.do")
public ModelAndView doSome(){
ModelAndView modelAndView = new ModelAndView();
//添加数据,框架在请求的最后把数据放到request作用域,
//request.setAttribute("msg","欢迎使用springmvc做web开发");
modelAndView.addObject("msg","欢迎使用springMvc做web开发");
modelAndView.addObject("fun","执行的是dpSome方法");
//指定视图,指定视图的完整路径
//框架对视图执行的forward操作,request.getRequestDiapather("/show.jsp").forward();
modelAndView.setViewName("/show.jsp");
//当配置了视图解析器,可以使用逻辑名称(文件名),指定视图
//框架会使用视图解析器前缀+后缀 组成完整路径,就是字符串连接
modelAndView.setViewName("show");
return modelAndView;
}
}
WEB_INF下的文件对用户是不开放的
普通类Controller的注解介绍
- 设置模块名称和请求方式
/**
1. @RequestMapping:
2. value:所有请求地址的公共部分,叫做模块名称
3. 位置放在类上
*/
@RequestMapping("/test")
@Controller
public class MyController {
/**
* @RequestMapping:请求映射
* 属性:method,表示请求参数,他的值RequestMethod类枚举值
* get-》RequestMethod.GET
* 如果没有表示method的值的话,对请求方式没有限制
*
* @return
*/
@RequestMapping(value = "/some.do",method = RequestMethod.GET)
public ModelAndView doSome(HttpServletRequest request,
HttpServletResponse response,
HttpSession session){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg","欢迎使用springMvc做web开发");
modelAndView.addObject("fun","执行的是dpSome方法");
modelAndView.setViewName("show");
return modelAndView;
}
}
- 接受请求参数
HttpServletRequest
HttpServletResponse
HttpSession
用户提交的数据
-----逐个接收
-----对象接收
/**
* 逐个接收请求参数:
* 要求:处理器(控制器)的方法的形参名和请求中参数名必须一致
* 同名的请求参数赋值给同名的形参
*框架接收请求参数:
* 1.使用request对象接受请求参数
* String strName = request.getParameter("name");
* String strAge = request.getParameter("age");
* 2.springmvc框架通过DispatcherServlet 调用MyController的doSome()方法
* 调用时,按名称对应,赋值给形参
* dosome(strName ,integer.valueof(strAge)
* 框架会提供类型转换的功能,将string转化为其他类型
*
* 400状态码是客户端错误,表示提交请求参数的过程中出现了问题
* @return
*/
@RequestMapping(value = "/some.do",method = RequestMethod.POST)
public ModelAndView doSome(String name,Integer age){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("myname",name);
modelAndView.addObject("myage",age);
modelAndView.setViewName("show");
return modelAndView;
}
- 设置过滤器,解决post乱码问题
<!-- 注册声明过滤器,解决post请求乱码的问题-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- 设置项目中使用的字符编码-->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<!-- 强制请求对象(HttpServletRequest)使用encoding编码的值-->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!-- 强制应答对象(HttpServletResponse)使用encoding编码的值-->
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<!-- 表示强制所有的请求先通过过滤器处理-->
<url-pattern>/*</url-pattern>
</filter-mapping>
- 解决请求中参数和形参名不一样的问题
/**
* @RequestParam:解决请求方法中形参名不一样的问题
* 属性:1.value:请求中的参数名称
* 2.required 是一个boolean,默认是true
* true:表示请求中必须包含此参数
* 位置:在处理器方法的形参定义的前面
*
*
* @param name
* @param age
* @return
*/
@RequestMapping(value = "/some.do",method = RequestMethod.POST)
public ModelAndView doSome(@RequestParam("pname") String name,
@RequestParam("page") Integer age){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("myname",name);
modelAndView.addObject("myage",age);
modelAndView.setViewName("show");
return modelAndView;
}
- 对象接收参数
/**
* 处理器方法形参是Java对象,这个对象的属性名和请求参数一样的
* 框架会创建形参的Java对象,给属性赋值,请求中的参数是name,框架会调用setName()
* @return
*/
@RequestMapping(value = "/some.do",method = RequestMethod.POST)
public ModelAndView doSome(Student myStudent){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("myname",myStudent.getName());
modelAndView.addObject("myage",myStudent.getAge());
modelAndView.setViewName("show");
return modelAndView;
}
- 返回值ModelAndView
如果处理器方法处理完后,需要跳转到其他资源,且又要在跳转的资源间传递数据,此时处理器方法返回ModelAndView较好,需要在方法中添加ModelAndView对象,否则有的多余
- 返回值String
String表示视图,可以逻辑名称,也可以是完整视图路径
/**
* 处理器方法返回String,表示逻辑视图名称,需要配置视图解析器
*
*/
@RequestMapping(value = "/some.do",method = RequestMethod.POST)
public String doSome(Student myStudent){
System.out.println("doReturnView,name="+myStudent.getName()+"age="+myStudent.getAge());
//show :逻辑视图名称,项目中配置了视图解析器
//如果使用完整的视图路径,项目中不能使用视图解析器
//框架对视图执行forward转发操作
return "show";
}
- 返回值是void(可以用于ajax )
不能表示数据,也不能表示视图
处理ajax时,可以使用void返回值,通过HttpServletRequest输出数据。响应ajax
ajax请求服务端返回的就是数据,和视图无关
//使用json和ajax
- 返回对象Object
返回对象,是数据和对象无关,可以响应ajax请求
/**
* 加入json依赖
* 在springmvc的配置文件中之间加入
* <mvc:annotation-driven>注解驱动
* 替代:json = om.writeValueAsString(student)
* 在处理器方法上面加上@ResponseBody注解
* response.setContentTyp("application/json;charset=utf-8”);
* PrintWriter pw = response.getWriter();
* pw.println(json);
**/
//springmvc处理器方法返回object,可以转为json输出到浏览器,响应ajax的内部原理
/**1.<mvc:annotation-driven> 注解驱动
1. 注解驱动实现的功能,完成java对象到json,xml,text,二进制等数据格式的转换
2. HttpMessageConverter接口:消息转换器
3. 功能:定义了Java转化为json,xml等数据格式的方法,这个接口有很多的实现类
4. 这些实现类完成java对象多json,java对象到xml,java对象到二进制数据的转换
5.
6. boolean canWrite(Class<?> var1, @Nullable MediaType var2);
7. 检查对象是为能转换为var2
8. void write(T var1, @Nullable MediaType var2, HttpOutputMessage var3)
9.
**/
- 返回List对象
//跟返回对象的方式是一样的
- 返回Map(一般不用)
- 返回String数据
/**
1. 处理器方法返回的是String,String表示数据,不是视图
2. 区分返回值是数据还是视图,看有没有@ResponseBody注解
3. 如果有注解,就是数据,不是视图
4. 5. 出现乱码问题,
6. 默认使用“text/plain;charset=iso-8859-1"作为contentType,导致有乱码
7. 解决方案:给ReuqestMapping增加一个属性produces,使用这个属性指定新的contentType
**/
补充:web中有一个default配置,加载静态资源和未映射到其他servlet的请求
访问静态资源的问题
中央调度器的地址使用"/"
当项目中使用了"/",会代替tomcat中的default,tomcat不会自动加载静态资源和未映射到其他servlet的请求
- 第一种静态资源处理方式
<!-- 第一种处理静态资源的方式
需要在springmvc配置文件加入 <mvc:default-servlet-handler/>
原理:加入这个标签后,框架会创建控制类对象DefaultServletHttpRequestHandler(类似于mycontroller)
DefaultServletHttpRequestHandler 可以将请求转给tomcat处理
-->
<mvc:default-servlet-handler/>
- 第二种静态资源处理方式
<!-- 第二种处理静态资源的方式
<mvc:resources 加入后框架会创建ResourceHttpRequestHandler对象
让这个对象访问静态资源,不依赖tomcat
mapping : 访问静态资源的uri地址,使用通配符**
location:静态资源在你的项目种的目录位置
-->
<mvc:resources mapping="/image/**" location="/image/" />
<mvc:resources mapping="/html/**" location="/html/" />
<mvc:resources mapping="/js/**" location="/js/" />
<!-- mvc:resources 和@RequestMapping有一定冲突-->
<mvc:annotation-driven/>
地址分类
- 绝对地址:带有协议名称的是绝对地址:http://www.baidu.com
- 相对地址:没有协议开头的,例如:user/some.do
相对地址不能独立使用,必须有一个参考地址,通过参考地址+相对地址本身才能指定资源
在index.jsp发起user/some.do请求,访问地址变为http://localhost:8080/ch06_path/user/some.do
当你的地址没有斜杠开头,例如user/some.do,当你点击链接时,访问的地址是当前页面的地址,加上链接的地址
http://localhost:8080/ch06_path/+user/some.do
当访问的地址加斜杠的话,/user/some.do,参考地址为http://localhost:8080/需要使用/ch06_path/user/some.do
解决访问地址的问题
- 加入${pageContext.request.contextPath},可以获得当前页面名称
- 加入一个base标签,是html语言中的标签,表示当前页面中,访问地址的基地址。界面中所有没有”/" 开头的地址,都是以base标签中的地址为参考地址
使用base中的地址+user/some.do
<%
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";
%>
<base href="<%basePath%>" />
异常处理
- springmvc框架采用的是统一的,全局的异常处理
2.把controller中的所有异常处理都集中到一个地方,采用aop的思想,把业务逻辑和异常处理的代码分开,解耦合
3.使用两个注解:
/**
* @ControllerAdvice:控制器增强
* 位置:类的上面
* 特点:必须让框架知道注解所在的包名,需要在springmvc中声明文件声明组件扫描器
* 指定@ControllerAdvice所在的包名
*
*/
@ControllerAdvice
public class GlobalExceptionHandler {
//定义方法,处理发生的异常
/**
* 处理异常的方法和控制器方法的定义一样,可以有多个参数,可以有ModelAndView
* String,void,对象类型的放回值
* 形参:Exception,表示Controller中抛出的异常对象
* 通过形参可以获取发生的异常信息
*
* @ExceptionHandler:表示异常的类型,当发生这个异常时,由当前方法处理
*/
@ExceptionHandler(NameException.class)
public ModelAndView doNameException(Exception ex){
//处理NameExceeptin异常
/**
* 异常发生处理逻辑,
* 1.需要把异常记录下来,记录到数据库,日志文件
* 记录日志放生的时间,放个方法发生的,异常错误内容
* 2.发送通知,把异常的信息通过邮件,短信,微信发送给相关人员
* 3,给用户友好提示
*/
return new ModelAndView();
}
//处理其他异常,不知到的类型异常
@ExceptionHandler
public ModelAndView doOtherException(Exception ex){
return new ModelAndView();
}
}
拦截器
1>拦截器是springmvc中的一种,需要实现HandlerInterceptor接口
2.拦截器和过滤器类似,过滤器是用来处理编码集和处理请求参数的
拦截器是用来拦截请求,对请求做判断处理的
3.拦截器是全局的,可以对多个Controller做拦截
一个项目可以有一个或者多个拦截器,通常用来用户登陆处理,权限检查,记录日志
拦截器的使用步骤
1.定义类实现HandlerInterceptor接口
2.在springmvc中声明拦截器
拦截器的执行时间
1.在请求处理之前,也就是controller类中方法的执行之前先被拦截
2.在控制器方法执行之后也会执行拦截器
3.在请求处理完成后也会执行拦截器
1.springmvc配置文件
<!-- 拦截器声明:可以有一个或者多个-->
<mvc:interceptors>
<!-- 声明一个拦截器-->
<mvc:interceptor>
<!-- 指定拦截的请求uri地址
path:就是url地址,可以使用通配符 **
-->
<mvc:mapping path="/test/**"/>
<bean class="com.yixia.handler.MyInterceptor">
</bean>
</mvc:interceptor>
</mvc:interceptors>
2.拦截器中方法的介绍
/**
* perHander:预处理方法
* 参数:
* Object handler:被拦截的控制器对象
* 返回值:boolean
* false:
* true:
* 特点:1.方法在控制器方法(MyController的dosome)之前先执行的
* 用户的请求首先到达此方法
* 2.在这个 方法中可以获取请求信息,验证请求是否符合要求
* 可以验证用户是否登录,是否有权力访问某个拦截地址
* 验证失败,拦截请求,请求不被处理
* 验证成果,请求放行,控制器方法才能执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器的MyInterceptor的preHandle方法");
return true;
}
/**
* postHandle:后处理方法
* 参数:
* Object handler:被拦截的控制器对象
* ModelAndView mv:处理器方法的返回值
*
* 特点:
* 1,在处理器方法之后执行的(MyController,doSome())
* 2。能够获取到处理方法的fanhuizhiModelAndView,可以修改ModelAndView中的
* 数据和视图,可以影响到最后的执行结果
* 3.主要是原来的执行结果做二次修正
*
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器的MyInterceptor的postHandle方法");
}
/**
* afterCompletion:最后执行的方法
* 参数:
* Object handler:被拦截的控制器对象
* Exception ex:程序中发生的异常
* 特点:
* 1.在请求处理完成后执行的,框架中规定是当你的视图处理完成后,对视图执行forward,就认为请求处理完成
* 2.一般做资源回收工作,程序请求过程中创建了一些对象,在这里可以删除,把占用的内存回收
*
*
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("拦截器的MyInterceptor的afterCompletion方法");
}
3.多个拦截器的执行顺序
有先后顺序
4.拦截器和过滤器的区别
1.过滤器是servlet中的对象,拦截器是框架中的对象
2.过滤器是tomcat服务器创建的对象,拦截器是springmvc容器中创建的对象
3.过滤器有一个执行点,拦截器有3个执行点
4.过滤器实现filter接口,拦截器实现HandlerInterceptor接口
5.过滤器是在拦截器之前先执行的,只有通过post方法才会通过中央调度器
6.过滤器可以处理jsp,js,html等,拦截器主要是针对Controller对象,如果请求不能被DispatcherServlet接收,这个请求不会被拦截器接收
springmvc内部处理请求的流程
1.用户发起请求
2.DispatcherServlet接受请求,把请求转发给处理器映射器,
-------处理器映射器,是springmvc中的对象,框架把实现了HandlerMapper的类都叫做映射器
------处理器映射器的作用,根据请求从springmvc容器中获取处理器对象,getbean,把找到的对象放到一个叫做处理器执行链的类中保存
---------HandlerExcutionChain:类中保存着,处理器对象(controller)和羡慕中所有的拦截器list
3.DispatcherServlet把执行链中的对象交给处理器适配器对象,
------处理器适配器:springmvc中的对象,需要是实现HandlerAdapter接口
处理器适配器作用,执行处理器方法,(Controller.dosome()方法执行)